@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
@@ -49,6 +49,7 @@ export class User extends UserBase {
|
|
49
49
|
private _LastLoginAt: Date;
|
50
50
|
private _MFAEnabled: number;
|
51
51
|
private _MFAConfig: string;
|
52
|
+
private _MFABypassYN: string;
|
52
53
|
private _RecoveryEmail: string;
|
53
54
|
private _FailedLoginAttemptCount: number;
|
54
55
|
private _LastFailedLoginAt: Date;
|
@@ -162,6 +163,14 @@ export class User extends UserBase {
|
|
162
163
|
this._MFAConfig = value;
|
163
164
|
}
|
164
165
|
|
166
|
+
get MFABypassYN(): string {
|
167
|
+
return this._MFABypassYN;
|
168
|
+
}
|
169
|
+
|
170
|
+
private set MFABypassYN(value: string) {
|
171
|
+
this._MFABypassYN = value;
|
172
|
+
}
|
173
|
+
|
165
174
|
get RecoveryEmail(): string {
|
166
175
|
return this._RecoveryEmail;
|
167
176
|
}
|
@@ -296,6 +305,7 @@ export class User extends UserBase {
|
|
296
305
|
this.LastLoginAt = userInfo.LastLoginAt;
|
297
306
|
this.MFAEnabled = userInfo.MFAEnabled;
|
298
307
|
this.MFAConfig = userInfo.MFAConfig;
|
308
|
+
this.MFABypassYN = userInfo.MFABypassYN;
|
299
309
|
this.RecoveryEmail = userInfo.RecoveryEmail;
|
300
310
|
this.FailedLoginAttemptCount = userInfo.FailedLoginAttemptCount;
|
301
311
|
this.LastFailedLoginAt = userInfo.LastFailedLoginAt;
|
@@ -352,6 +362,7 @@ export class User extends UserBase {
|
|
352
362
|
LastLoginAt: user.LastLoginAt,
|
353
363
|
MFAEnabled: user.MFAEnabled,
|
354
364
|
MFAConfig: user.MFAConfig,
|
365
|
+
MFABypassYN: user.MFABypassYN,
|
355
366
|
RecoveryEmail: user.RecoveryEmail,
|
356
367
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
357
368
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -416,6 +427,7 @@ export class User extends UserBase {
|
|
416
427
|
LastLoginAt: user.LastLoginAt,
|
417
428
|
MFAEnabled: user.MFAEnabled,
|
418
429
|
MFAConfig: user.MFAConfig,
|
430
|
+
MFABypassYN: user.MFABypassYN,
|
419
431
|
RecoveryEmail: user.RecoveryEmail,
|
420
432
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
421
433
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -510,6 +522,7 @@ export class User extends UserBase {
|
|
510
522
|
LastLoginAt: user.LastLoginAt,
|
511
523
|
MFAEnabled: user.MFAEnabled,
|
512
524
|
MFAConfig: user.MFAConfig,
|
525
|
+
MFABypassYN: user.MFABypassYN,
|
513
526
|
RecoveryEmail: user.RecoveryEmail,
|
514
527
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
515
528
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -547,13 +560,11 @@ export class User extends UserBase {
|
|
547
560
|
this.UpdatedAt = userAttr.UpdatedAt;
|
548
561
|
this.staffs = userAttr.staffs;
|
549
562
|
} else {
|
550
|
-
console.error('User not found for email:', email);
|
551
563
|
throw new ClassError('User', 'UserErrMsg0X', 'Invalid Credentials');
|
552
564
|
}
|
553
565
|
}
|
554
566
|
|
555
567
|
if (this.ObjectId && this.Email !== email) {
|
556
|
-
console.error('Email mismatch:', this.Email, email);
|
557
568
|
throw new Error('Invalid credentials.');
|
558
569
|
}
|
559
570
|
|
@@ -574,8 +585,7 @@ export class User extends UserBase {
|
|
574
585
|
},
|
575
586
|
});
|
576
587
|
if (!system) {
|
577
|
-
|
578
|
-
throw new Error('Invalid credentials.');
|
588
|
+
throw new Error('Access denied: invalid or unauthorized system.');
|
579
589
|
}
|
580
590
|
|
581
591
|
// 1.5: Instantiate new PasswordHashService object and call PasswordHashService.verify method to check whether the param.Password is correct.
|
@@ -586,7 +596,6 @@ export class User extends UserBase {
|
|
586
596
|
this.Password,
|
587
597
|
);
|
588
598
|
if (!isPasswordValid) {
|
589
|
-
console.error('Invalid password for user:', this.UserId);
|
590
599
|
throw new Error('Invalid credentials.');
|
591
600
|
}
|
592
601
|
|
@@ -605,14 +614,14 @@ export class User extends UserBase {
|
|
605
614
|
await User.releaseLock(this.UserId, dbTransaction);
|
606
615
|
this.Status = UserStatus.ACTIVE;
|
607
616
|
} else {
|
608
|
-
|
609
|
-
|
617
|
+
throw new Error(
|
618
|
+
'Your account has been locked. Please contact the administrator for assistance.',
|
619
|
+
);
|
610
620
|
}
|
611
621
|
}
|
612
622
|
} catch (error) {
|
613
623
|
await this.incrementFailedLoginAttemptCount(dbTransaction);
|
614
|
-
|
615
|
-
throw new Error('Invalid credentials.');
|
624
|
+
throw error;
|
616
625
|
}
|
617
626
|
|
618
627
|
// 2.1: Call alertNewLogin to check whether the ip used is new ip and alert the user if it's new.
|
@@ -667,7 +676,6 @@ export class User extends UserBase {
|
|
667
676
|
ApplicationConfig.getComponentConfigValue('sessionName');
|
668
677
|
|
669
678
|
if (!sessionName) {
|
670
|
-
console.error('Session name is not set in the configuration');
|
671
679
|
throw new Error('Session name is not set in the configuration');
|
672
680
|
}
|
673
681
|
|
@@ -759,7 +767,6 @@ export class User extends UserBase {
|
|
759
767
|
},
|
760
768
|
);
|
761
769
|
}
|
762
|
-
console.error('Login failed:', error);
|
763
770
|
throw error;
|
764
771
|
}
|
765
772
|
}
|
@@ -798,7 +805,7 @@ export class User extends UserBase {
|
|
798
805
|
dbTransaction,
|
799
806
|
});
|
800
807
|
|
801
|
-
|
808
|
+
for (const usergroup of userGroups) {
|
802
809
|
const group = usergroup.Group;
|
803
810
|
const groupSystemAccess = await User.getInheritedSystemAccess(
|
804
811
|
dbTransaction,
|
@@ -808,7 +815,7 @@ export class User extends UserBase {
|
|
808
815
|
for (const system of groupSystemAccess) {
|
809
816
|
if (system.SystemCode === systemCode) {
|
810
817
|
isUserHaveAccess = true;
|
811
|
-
break
|
818
|
+
break;
|
812
819
|
}
|
813
820
|
}
|
814
821
|
}
|
@@ -818,7 +825,6 @@ export class User extends UserBase {
|
|
818
825
|
throw new Error("User don't have access to the system.");
|
819
826
|
}
|
820
827
|
} catch (error) {
|
821
|
-
console.error('Error checking system access:', error);
|
822
828
|
throw error;
|
823
829
|
}
|
824
830
|
}
|
@@ -1580,6 +1586,7 @@ export class User extends UserBase {
|
|
1580
1586
|
LastLoginAt: null,
|
1581
1587
|
MFAEnabled: null,
|
1582
1588
|
MFAConfig: null,
|
1589
|
+
MFABypassYN: YN.No,
|
1583
1590
|
RecoveryEmail: null,
|
1584
1591
|
FailedLoginAttemptCount: 0,
|
1585
1592
|
LastFailedLoginAt: null,
|
@@ -1727,7 +1734,7 @@ export class User extends UserBase {
|
|
1727
1734
|
throw new ClassError(
|
1728
1735
|
'LoginUser',
|
1729
1736
|
'LoginUserErrMsg0X',
|
1730
|
-
'
|
1737
|
+
'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account.',
|
1731
1738
|
);
|
1732
1739
|
}
|
1733
1740
|
}
|
@@ -1813,7 +1820,7 @@ export class User extends UserBase {
|
|
1813
1820
|
|
1814
1821
|
// Part 2: Retrieve Parent Group System Access If Applicable
|
1815
1822
|
// 2.1 Check if Params.group.InheritParentSystemAccessYN is "Y" and Params.group.ParentGroupCode is not empty
|
1816
|
-
if (group.
|
1823
|
+
if (group.InheritParentSystemAccessYN === 'Y' && group.ParentGroupCode) {
|
1817
1824
|
const GroupCode = group.ParentGroupCode;
|
1818
1825
|
const parentGroup = await User._GroupRepo.findByPk(
|
1819
1826
|
GroupCode,
|
@@ -1998,15 +2005,31 @@ export class User extends UserBase {
|
|
1998
2005
|
}
|
1999
2006
|
|
2000
2007
|
// 3. Verify the mfaToken by calling speakeasy.totp.verify
|
2001
|
-
const
|
2008
|
+
const isCurrentValid = await speakeasy.totp.verify({
|
2002
2009
|
secret: userMFAConfig.totp.secret,
|
2003
2010
|
encoding: 'base32',
|
2004
2011
|
token: mfaToken,
|
2012
|
+
window: 0, // strict current time window
|
2005
2013
|
});
|
2014
|
+
if (!isCurrentValid) {
|
2015
|
+
const isExpired = await speakeasy.totp.verify({
|
2016
|
+
secret: userMFAConfig.totp.secret,
|
2017
|
+
encoding: 'base32',
|
2018
|
+
token: mfaToken,
|
2019
|
+
window: 2, // allow slight leeway: previous or next 2 time steps
|
2020
|
+
});
|
2006
2021
|
|
2007
|
-
|
2008
|
-
|
2009
|
-
|
2022
|
+
if (isExpired) {
|
2023
|
+
return {
|
2024
|
+
success: false,
|
2025
|
+
reason: 'MFA token has expired. Please try again.',
|
2026
|
+
};
|
2027
|
+
} else {
|
2028
|
+
return {
|
2029
|
+
success: false,
|
2030
|
+
reason: 'Invalid MFA token. Check your authenticator app.',
|
2031
|
+
};
|
2032
|
+
}
|
2010
2033
|
}
|
2011
2034
|
|
2012
2035
|
user.MFAEnabled = 1;
|
@@ -2035,7 +2058,7 @@ export class User extends UserBase {
|
|
2035
2058
|
const systemLogin = userSession.systemLogins.find(
|
2036
2059
|
(e) => e.code === systemCode,
|
2037
2060
|
);
|
2038
|
-
return `${userId}:${systemLogin.sessionId}
|
2061
|
+
return { success: true, sessionId: `${userId}:${systemLogin.sessionId}` };
|
2039
2062
|
}
|
2040
2063
|
|
2041
2064
|
// This method will verify 2FA codes
|
@@ -2073,15 +2096,31 @@ export class User extends UserBase {
|
|
2073
2096
|
}
|
2074
2097
|
|
2075
2098
|
// 3. Verify the mfaToken by calling speakeasy.totp.verify
|
2076
|
-
const
|
2099
|
+
const isCurrentValid = await speakeasy.totp.verify({
|
2077
2100
|
secret: userMFAConfig.totp.secret,
|
2078
2101
|
encoding: 'base32',
|
2079
2102
|
token: mfaToken,
|
2103
|
+
window: 0, // strict current time window
|
2080
2104
|
});
|
2105
|
+
if (!isCurrentValid) {
|
2106
|
+
const isExpired = await speakeasy.totp.verify({
|
2107
|
+
secret: userMFAConfig.totp.secret,
|
2108
|
+
encoding: 'base32',
|
2109
|
+
token: mfaToken,
|
2110
|
+
window: 2, // allow slight leeway: previous or next 2 time steps
|
2111
|
+
});
|
2081
2112
|
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2113
|
+
if (isExpired) {
|
2114
|
+
return {
|
2115
|
+
success: false,
|
2116
|
+
reason: 'MFA token has expired. Please try again.',
|
2117
|
+
};
|
2118
|
+
} else {
|
2119
|
+
return {
|
2120
|
+
success: false,
|
2121
|
+
reason: 'Invalid MFA token. Check your authenticator app.',
|
2122
|
+
};
|
2123
|
+
}
|
2085
2124
|
}
|
2086
2125
|
|
2087
2126
|
// 5. Retrieve Session
|
@@ -2104,7 +2143,7 @@ export class User extends UserBase {
|
|
2104
2143
|
const systemLogin = userSession.systemLogins.find(
|
2105
2144
|
(e) => e.code === systemCode,
|
2106
2145
|
);
|
2107
|
-
return `${userId}:${systemLogin.sessionId}
|
2146
|
+
return { success: true, sessionId: `${userId}:${systemLogin.sessionId}` };
|
2108
2147
|
}
|
2109
2148
|
|
2110
2149
|
public async bypass2FA(systemCode: string, dbTransaction: any) {
|
@@ -2147,7 +2186,10 @@ export class User extends UserBase {
|
|
2147
2186
|
const systemLogin = userSession.systemLogins.find(
|
2148
2187
|
(e) => e.code === systemCode,
|
2149
2188
|
);
|
2150
|
-
return
|
2189
|
+
return {
|
2190
|
+
success: true,
|
2191
|
+
sessionId: `${this.UserId}:${systemLogin.sessionId}`,
|
2192
|
+
};
|
2151
2193
|
} catch (error) {
|
2152
2194
|
throw error;
|
2153
2195
|
}
|
@@ -2610,6 +2652,7 @@ export class User extends UserBase {
|
|
2610
2652
|
LastLoginAt: user.LastLoginAt,
|
2611
2653
|
MFAEnabled: user.MFAEnabled,
|
2612
2654
|
MFAConfig: user.MFAConfig,
|
2655
|
+
MFABypassYN: user.MFABypassYN,
|
2613
2656
|
RecoveryEmail: user.RecoveryEmail,
|
2614
2657
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
2615
2658
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -2736,6 +2779,7 @@ export class User extends UserBase {
|
|
2736
2779
|
LastLoginAt: user.LastLoginAt,
|
2737
2780
|
MFAEnabled: user.MFAEnabled,
|
2738
2781
|
MFAConfig: user.MFAConfig,
|
2782
|
+
MFABypassYN: user.MFABypassYN,
|
2739
2783
|
RecoveryEmail: user.RecoveryEmail,
|
2740
2784
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
2741
2785
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -2799,6 +2843,7 @@ export class User extends UserBase {
|
|
2799
2843
|
LastLoginAt: this.LastLoginAt,
|
2800
2844
|
MFAEnabled: this.MFAEnabled,
|
2801
2845
|
MFAConfig: this.MFAConfig,
|
2846
|
+
MFABypassYN: this.MFABypassYN,
|
2802
2847
|
RecoveryEmail: this.RecoveryEmail,
|
2803
2848
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2804
2849
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -2830,6 +2875,7 @@ export class User extends UserBase {
|
|
2830
2875
|
LastLoginAt: this.LastLoginAt,
|
2831
2876
|
MFAEnabled: this.MFAEnabled,
|
2832
2877
|
MFAConfig: this.MFAConfig,
|
2878
|
+
MFABypassYN: this.MFABypassYN,
|
2833
2879
|
RecoveryEmail: this.RecoveryEmail,
|
2834
2880
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2835
2881
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -2920,6 +2966,7 @@ export class User extends UserBase {
|
|
2920
2966
|
LastLoginAt: this.LastLoginAt,
|
2921
2967
|
MFAEnabled: this.MFAEnabled,
|
2922
2968
|
MFAConfig: this.MFAConfig,
|
2969
|
+
MFABypassYN: this.MFABypassYN,
|
2923
2970
|
RecoveryEmail: this.RecoveryEmail,
|
2924
2971
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2925
2972
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -2951,6 +2998,7 @@ export class User extends UserBase {
|
|
2951
2998
|
LastLoginAt: this.LastLoginAt,
|
2952
2999
|
MFAEnabled: this.MFAEnabled,
|
2953
3000
|
MFAConfig: this.MFAConfig,
|
3001
|
+
MFABypassYN: this.MFABypassYN,
|
2954
3002
|
RecoveryEmail: this.RecoveryEmail,
|
2955
3003
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2956
3004
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -3140,4 +3188,370 @@ export class User extends UserBase {
|
|
3140
3188
|
throw error;
|
3141
3189
|
}
|
3142
3190
|
}
|
3191
|
+
|
3192
|
+
public async enable2FABypass(loginUser: LoginUser, dbTransaction: any) {
|
3193
|
+
try {
|
3194
|
+
// 1. Check if MFABypassYN is already enabled
|
3195
|
+
if (this.MFABypassYN === YN.Yes) {
|
3196
|
+
throw new ClassError(
|
3197
|
+
'User',
|
3198
|
+
'UserErrMsg0X',
|
3199
|
+
'Bypass already enabled.',
|
3200
|
+
'enable2FABypass',
|
3201
|
+
);
|
3202
|
+
}
|
3203
|
+
|
3204
|
+
// 2. Check if user has MANAGE_MFA privilege
|
3205
|
+
const systemCode =
|
3206
|
+
ApplicationConfig.getComponentConfigValue('system-code');
|
3207
|
+
const isPrivileged = await loginUser.checkPrivileges(
|
3208
|
+
systemCode,
|
3209
|
+
'MANAGE_MFA',
|
3210
|
+
);
|
3211
|
+
if (!isPrivileged) {
|
3212
|
+
throw new ClassError(
|
3213
|
+
'LoginUser',
|
3214
|
+
'LoginUserErrMsg0X',
|
3215
|
+
'You do not have permission to enable MFA bypass.',
|
3216
|
+
);
|
3217
|
+
}
|
3218
|
+
|
3219
|
+
const entityValueBefore: IUserAttr = {
|
3220
|
+
UserId: this.UserId,
|
3221
|
+
UserName: this.UserName,
|
3222
|
+
FullName: this.FullName,
|
3223
|
+
IDNo: this.IDNo,
|
3224
|
+
IDType: this.IDType,
|
3225
|
+
ContactNo: this.ContactNo,
|
3226
|
+
Email: this.Email,
|
3227
|
+
Password: this.Password,
|
3228
|
+
Status: this.Status,
|
3229
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
3230
|
+
FirstLoginAt: this.FirstLoginAt,
|
3231
|
+
LastLoginAt: this.LastLoginAt,
|
3232
|
+
MFAEnabled: this.MFAEnabled,
|
3233
|
+
MFAConfig: this.MFAConfig,
|
3234
|
+
MFABypassYN: this.MFABypassYN,
|
3235
|
+
RecoveryEmail: this.RecoveryEmail,
|
3236
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
3237
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
3238
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
3239
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
3240
|
+
CreatedById: this.CreatedById,
|
3241
|
+
CreatedAt: this.CreatedAt,
|
3242
|
+
UpdatedById: this.UpdatedById,
|
3243
|
+
UpdatedAt: this.UpdatedAt,
|
3244
|
+
PasscodeHash: this.PasscodeHash,
|
3245
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
3246
|
+
};
|
3247
|
+
|
3248
|
+
// 3. Update user record
|
3249
|
+
this.MFABypassYN = YN.Yes;
|
3250
|
+
this.MFAEnabled = 0;
|
3251
|
+
this.UpdatedAt = new Date();
|
3252
|
+
this.UpdatedById = loginUser.UserId;
|
3253
|
+
|
3254
|
+
await User._Repository.update(
|
3255
|
+
{
|
3256
|
+
MFABypassYN: this.MFABypassYN,
|
3257
|
+
MFAEnabled: this.MFAEnabled,
|
3258
|
+
UpdatedAt: this.UpdatedAt,
|
3259
|
+
UpdatedById: this.UpdatedById,
|
3260
|
+
},
|
3261
|
+
{
|
3262
|
+
where: {
|
3263
|
+
UserId: this.UserId,
|
3264
|
+
},
|
3265
|
+
transaction: dbTransaction,
|
3266
|
+
},
|
3267
|
+
);
|
3268
|
+
|
3269
|
+
const entityValueAfter: IUserAttr = {
|
3270
|
+
UserId: this.UserId,
|
3271
|
+
UserName: this.UserName,
|
3272
|
+
FullName: this.FullName,
|
3273
|
+
IDNo: this.IDNo,
|
3274
|
+
IDType: this.IDType,
|
3275
|
+
ContactNo: this.ContactNo,
|
3276
|
+
Email: this.Email,
|
3277
|
+
Password: this.Password,
|
3278
|
+
Status: this.Status,
|
3279
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
3280
|
+
FirstLoginAt: this.FirstLoginAt,
|
3281
|
+
LastLoginAt: this.LastLoginAt,
|
3282
|
+
MFAEnabled: this.MFAEnabled,
|
3283
|
+
MFAConfig: this.MFAConfig,
|
3284
|
+
MFABypassYN: this.MFABypassYN,
|
3285
|
+
RecoveryEmail: this.RecoveryEmail,
|
3286
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
3287
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
3288
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
3289
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
3290
|
+
CreatedById: this.CreatedById,
|
3291
|
+
CreatedAt: this.CreatedAt,
|
3292
|
+
UpdatedById: this.UpdatedById,
|
3293
|
+
UpdatedAt: this.UpdatedAt,
|
3294
|
+
PasscodeHash: this.PasscodeHash,
|
3295
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
3296
|
+
};
|
3297
|
+
|
3298
|
+
// Record update activity using Activity class create method.
|
3299
|
+
const activity = new Activity();
|
3300
|
+
activity.ActivityId = activity.createId();
|
3301
|
+
activity.Action = ActionEnum.UPDATE;
|
3302
|
+
activity.Description = `Enable 2FA Bypass For User ${this.Email}`;
|
3303
|
+
activity.EntityType = this.ObjectType;
|
3304
|
+
activity.EntityId = this.UserId.toString();
|
3305
|
+
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
|
3306
|
+
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
|
3307
|
+
|
3308
|
+
await activity.create(loginUser.ObjectId, dbTransaction);
|
3309
|
+
} catch (error) {
|
3310
|
+
throw error;
|
3311
|
+
}
|
3312
|
+
}
|
3313
|
+
|
3314
|
+
public async disable2FABypass(loginUser: LoginUser, dbTransaction: any) {
|
3315
|
+
try {
|
3316
|
+
// 1. Check if MFABypassYN is already disabled
|
3317
|
+
if (this.MFABypassYN === YN.No) {
|
3318
|
+
throw new ClassError(
|
3319
|
+
'User',
|
3320
|
+
'UserErrMsg0X',
|
3321
|
+
'Bypass already disabled.',
|
3322
|
+
'disable2FABypass',
|
3323
|
+
);
|
3324
|
+
}
|
3325
|
+
|
3326
|
+
// 2. Check if user has MANAGE_MFA privilege
|
3327
|
+
const systemCode =
|
3328
|
+
ApplicationConfig.getComponentConfigValue('system-code');
|
3329
|
+
const isPrivileged = await loginUser.checkPrivileges(
|
3330
|
+
systemCode,
|
3331
|
+
'MANAGE_MFA',
|
3332
|
+
);
|
3333
|
+
if (!isPrivileged) {
|
3334
|
+
throw new ClassError(
|
3335
|
+
'LoginUser',
|
3336
|
+
'LoginUserErrMsg0X',
|
3337
|
+
'You do not have permission to enable MFA bypass.',
|
3338
|
+
);
|
3339
|
+
}
|
3340
|
+
|
3341
|
+
const entityValueBefore: IUserAttr = {
|
3342
|
+
UserId: this.UserId,
|
3343
|
+
UserName: this.UserName,
|
3344
|
+
FullName: this.FullName,
|
3345
|
+
IDNo: this.IDNo,
|
3346
|
+
IDType: this.IDType,
|
3347
|
+
ContactNo: this.ContactNo,
|
3348
|
+
Email: this.Email,
|
3349
|
+
Password: this.Password,
|
3350
|
+
Status: this.Status,
|
3351
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
3352
|
+
FirstLoginAt: this.FirstLoginAt,
|
3353
|
+
LastLoginAt: this.LastLoginAt,
|
3354
|
+
MFAEnabled: this.MFAEnabled,
|
3355
|
+
MFAConfig: this.MFAConfig,
|
3356
|
+
MFABypassYN: this.MFABypassYN,
|
3357
|
+
RecoveryEmail: this.RecoveryEmail,
|
3358
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
3359
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
3360
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
3361
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
3362
|
+
CreatedById: this.CreatedById,
|
3363
|
+
CreatedAt: this.CreatedAt,
|
3364
|
+
UpdatedById: this.UpdatedById,
|
3365
|
+
UpdatedAt: this.UpdatedAt,
|
3366
|
+
PasscodeHash: this.PasscodeHash,
|
3367
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
3368
|
+
};
|
3369
|
+
|
3370
|
+
// 3. Update user record
|
3371
|
+
this.MFABypassYN = YN.No;
|
3372
|
+
this.MFAEnabled = 0;
|
3373
|
+
this.UpdatedAt = new Date();
|
3374
|
+
this.UpdatedById = loginUser.UserId;
|
3375
|
+
|
3376
|
+
await User._Repository.update(
|
3377
|
+
{
|
3378
|
+
MFABypassYN: this.MFABypassYN,
|
3379
|
+
MFAEnabled: this.MFAEnabled,
|
3380
|
+
UpdatedAt: this.UpdatedAt,
|
3381
|
+
UpdatedById: this.UpdatedById,
|
3382
|
+
},
|
3383
|
+
{
|
3384
|
+
where: {
|
3385
|
+
UserId: this.UserId,
|
3386
|
+
},
|
3387
|
+
transaction: dbTransaction,
|
3388
|
+
},
|
3389
|
+
);
|
3390
|
+
|
3391
|
+
const entityValueAfter: IUserAttr = {
|
3392
|
+
UserId: this.UserId,
|
3393
|
+
UserName: this.UserName,
|
3394
|
+
FullName: this.FullName,
|
3395
|
+
IDNo: this.IDNo,
|
3396
|
+
IDType: this.IDType,
|
3397
|
+
ContactNo: this.ContactNo,
|
3398
|
+
Email: this.Email,
|
3399
|
+
Password: this.Password,
|
3400
|
+
Status: this.Status,
|
3401
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
3402
|
+
FirstLoginAt: this.FirstLoginAt,
|
3403
|
+
LastLoginAt: this.LastLoginAt,
|
3404
|
+
MFAEnabled: this.MFAEnabled,
|
3405
|
+
MFAConfig: this.MFAConfig,
|
3406
|
+
MFABypassYN: this.MFABypassYN,
|
3407
|
+
RecoveryEmail: this.RecoveryEmail,
|
3408
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
3409
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
3410
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
3411
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
3412
|
+
CreatedById: this.CreatedById,
|
3413
|
+
CreatedAt: this.CreatedAt,
|
3414
|
+
UpdatedById: this.UpdatedById,
|
3415
|
+
UpdatedAt: this.UpdatedAt,
|
3416
|
+
PasscodeHash: this.PasscodeHash,
|
3417
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
3418
|
+
};
|
3419
|
+
|
3420
|
+
// Record update activity using Activity class create method.
|
3421
|
+
const activity = new Activity();
|
3422
|
+
activity.ActivityId = activity.createId();
|
3423
|
+
activity.Action = ActionEnum.UPDATE;
|
3424
|
+
activity.Description = `Disable 2FA Bypass For User ${this.Email}`;
|
3425
|
+
activity.EntityType = this.ObjectType;
|
3426
|
+
activity.EntityId = this.UserId.toString();
|
3427
|
+
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
|
3428
|
+
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
|
3429
|
+
|
3430
|
+
await activity.create(loginUser.ObjectId, dbTransaction);
|
3431
|
+
} catch (error) {
|
3432
|
+
throw error;
|
3433
|
+
}
|
3434
|
+
}
|
3435
|
+
|
3436
|
+
public async reset2FA(loginUser: LoginUser, dbTransaction: any) {
|
3437
|
+
try {
|
3438
|
+
// 1. Check if MFABypassYN is already disabled
|
3439
|
+
if (this.MFAEnabled === 0) {
|
3440
|
+
throw new ClassError(
|
3441
|
+
'User',
|
3442
|
+
'UserErrMsg0X',
|
3443
|
+
'User not yet setup 2FA.',
|
3444
|
+
'reset2FA',
|
3445
|
+
);
|
3446
|
+
}
|
3447
|
+
|
3448
|
+
// 2. Check if user has MANAGE_MFA privilege
|
3449
|
+
const systemCode =
|
3450
|
+
ApplicationConfig.getComponentConfigValue('system-code');
|
3451
|
+
const isPrivileged = await loginUser.checkPrivileges(
|
3452
|
+
systemCode,
|
3453
|
+
'MANAGE_MFA',
|
3454
|
+
);
|
3455
|
+
if (!isPrivileged) {
|
3456
|
+
throw new ClassError(
|
3457
|
+
'LoginUser',
|
3458
|
+
'LoginUserErrMsg0X',
|
3459
|
+
'You do not have permission to reset 2FA.',
|
3460
|
+
);
|
3461
|
+
}
|
3462
|
+
|
3463
|
+
const entityValueBefore: IUserAttr = {
|
3464
|
+
UserId: this.UserId,
|
3465
|
+
UserName: this.UserName,
|
3466
|
+
FullName: this.FullName,
|
3467
|
+
IDNo: this.IDNo,
|
3468
|
+
IDType: this.IDType,
|
3469
|
+
ContactNo: this.ContactNo,
|
3470
|
+
Email: this.Email,
|
3471
|
+
Password: this.Password,
|
3472
|
+
Status: this.Status,
|
3473
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
3474
|
+
FirstLoginAt: this.FirstLoginAt,
|
3475
|
+
LastLoginAt: this.LastLoginAt,
|
3476
|
+
MFAEnabled: this.MFAEnabled,
|
3477
|
+
MFAConfig: this.MFAConfig,
|
3478
|
+
MFABypassYN: this.MFABypassYN,
|
3479
|
+
RecoveryEmail: this.RecoveryEmail,
|
3480
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
3481
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
3482
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
3483
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
3484
|
+
CreatedById: this.CreatedById,
|
3485
|
+
CreatedAt: this.CreatedAt,
|
3486
|
+
UpdatedById: this.UpdatedById,
|
3487
|
+
UpdatedAt: this.UpdatedAt,
|
3488
|
+
PasscodeHash: this.PasscodeHash,
|
3489
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
3490
|
+
};
|
3491
|
+
|
3492
|
+
// 3. Update user record
|
3493
|
+
this.MFAEnabled = 0;
|
3494
|
+
this.MFABypassYN = YN.No;
|
3495
|
+
this.UpdatedAt = new Date();
|
3496
|
+
this.UpdatedById = loginUser.UserId;
|
3497
|
+
|
3498
|
+
await User._Repository.update(
|
3499
|
+
{
|
3500
|
+
MFAEnabled: this.MFAEnabled,
|
3501
|
+
MFABypassYN: this.MFABypassYN,
|
3502
|
+
UpdatedAt: this.UpdatedAt,
|
3503
|
+
UpdatedById: this.UpdatedById,
|
3504
|
+
},
|
3505
|
+
{
|
3506
|
+
where: {
|
3507
|
+
UserId: this.UserId,
|
3508
|
+
},
|
3509
|
+
transaction: dbTransaction,
|
3510
|
+
},
|
3511
|
+
);
|
3512
|
+
|
3513
|
+
const entityValueAfter: IUserAttr = {
|
3514
|
+
UserId: this.UserId,
|
3515
|
+
UserName: this.UserName,
|
3516
|
+
FullName: this.FullName,
|
3517
|
+
IDNo: this.IDNo,
|
3518
|
+
IDType: this.IDType,
|
3519
|
+
ContactNo: this.ContactNo,
|
3520
|
+
Email: this.Email,
|
3521
|
+
Password: this.Password,
|
3522
|
+
Status: this.Status,
|
3523
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
3524
|
+
FirstLoginAt: this.FirstLoginAt,
|
3525
|
+
LastLoginAt: this.LastLoginAt,
|
3526
|
+
MFAEnabled: this.MFAEnabled,
|
3527
|
+
MFAConfig: this.MFAConfig,
|
3528
|
+
MFABypassYN: this.MFABypassYN,
|
3529
|
+
RecoveryEmail: this.RecoveryEmail,
|
3530
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
3531
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
3532
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
3533
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
3534
|
+
CreatedById: this.CreatedById,
|
3535
|
+
CreatedAt: this.CreatedAt,
|
3536
|
+
UpdatedById: this.UpdatedById,
|
3537
|
+
UpdatedAt: this.UpdatedAt,
|
3538
|
+
PasscodeHash: this.PasscodeHash,
|
3539
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
3540
|
+
};
|
3541
|
+
|
3542
|
+
// Record update activity using Activity class create method.
|
3543
|
+
const activity = new Activity();
|
3544
|
+
activity.ActivityId = activity.createId();
|
3545
|
+
activity.Action = ActionEnum.UPDATE;
|
3546
|
+
activity.Description = `Reset 2FA for User ${this.Email}`;
|
3547
|
+
activity.EntityType = this.ObjectType;
|
3548
|
+
activity.EntityId = this.UserId.toString();
|
3549
|
+
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
|
3550
|
+
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
|
3551
|
+
|
3552
|
+
await activity.create(loginUser.ObjectId, dbTransaction);
|
3553
|
+
} catch (error) {
|
3554
|
+
throw error;
|
3555
|
+
}
|
3556
|
+
}
|
3143
3557
|
}
|