@tomei/sso 0.60.4-dev.6 → 0.60.4-dev.8

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.
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, Sequelize) => {
5
+ const transaction = await queryInterface.sequelize.transaction();
6
+ try {
7
+ await queryInterface.addColumn('sso_User', 'MFABypassYN', {
8
+ type: Sequelize.CHAR(1),
9
+ allowNull: false,
10
+ defaultValue: 'N',
11
+ });
12
+
13
+ await transaction.commit();
14
+ } catch (error) {
15
+ await transaction.rollback();
16
+ throw error;
17
+ }
18
+ },
19
+
20
+ down: async (queryInterface, Sequelize) => {
21
+ const transaction = await queryInterface.sequelize.transaction();
22
+ try {
23
+ await queryInterface.removeColumn('sso_User', 'MFABypassYN');
24
+ await transaction.commit();
25
+ } catch (error) {
26
+ await transaction.rollback();
27
+ throw error;
28
+ }
29
+ },
30
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomei/sso",
3
- "version": "0.60.4-dev.6",
3
+ "version": "0.60.4-dev.8",
4
4
  "description": "Tomei SSO Package",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -74,6 +74,11 @@ export class LoginHistory extends ObjectBase {
74
74
  return;
75
75
  }
76
76
 
77
+ if (key === 'UserId') {
78
+ queryObj[key] = value; // Directly assign UserId
79
+ return;
80
+ }
81
+
77
82
  queryObj[key] = {
78
83
  [Op.substring]: value,
79
84
  };
@@ -20,6 +20,7 @@ export interface IUserAttr extends IUserInfo {
20
20
  LastLoginAt: Date;
21
21
  MFAEnabled: number;
22
22
  MFAConfig: string;
23
+ MFABypassYN: string;
23
24
  RecoveryEmail: string;
24
25
  FailedLoginAttemptCount: number;
25
26
  LastFailedLoginAt: Date;
@@ -61,6 +61,7 @@ export class LoginUser extends User implements ILoginUser {
61
61
  LastLoginAt: user.LastLoginAt,
62
62
  MFAEnabled: user.MFAEnabled,
63
63
  MFAConfig: user.MFAConfig,
64
+ MFABypassYN: user.MFABypassYN,
64
65
  RecoveryEmail: user.RecoveryEmail,
65
66
  FailedLoginAttemptCount: user.FailedLoginAttemptCount,
66
67
  LastFailedLoginAt: user.LastFailedLoginAt,
@@ -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,
@@ -1571,6 +1584,7 @@ export class User extends UserBase {
1571
1584
  LastLoginAt: null,
1572
1585
  MFAEnabled: null,
1573
1586
  MFAConfig: null,
1587
+ MFABypassYN: YN.No,
1574
1588
  RecoveryEmail: null,
1575
1589
  FailedLoginAttemptCount: 0,
1576
1590
  LastFailedLoginAt: null,
@@ -2601,6 +2615,7 @@ export class User extends UserBase {
2601
2615
  LastLoginAt: user.LastLoginAt,
2602
2616
  MFAEnabled: user.MFAEnabled,
2603
2617
  MFAConfig: user.MFAConfig,
2618
+ MFABypassYN: user.MFABypassYN,
2604
2619
  RecoveryEmail: user.RecoveryEmail,
2605
2620
  FailedLoginAttemptCount: user.FailedLoginAttemptCount,
2606
2621
  LastFailedLoginAt: user.LastFailedLoginAt,
@@ -2727,6 +2742,7 @@ export class User extends UserBase {
2727
2742
  LastLoginAt: user.LastLoginAt,
2728
2743
  MFAEnabled: user.MFAEnabled,
2729
2744
  MFAConfig: user.MFAConfig,
2745
+ MFABypassYN: user.MFABypassYN,
2730
2746
  RecoveryEmail: user.RecoveryEmail,
2731
2747
  FailedLoginAttemptCount: user.FailedLoginAttemptCount,
2732
2748
  LastFailedLoginAt: user.LastFailedLoginAt,
@@ -2790,6 +2806,7 @@ export class User extends UserBase {
2790
2806
  LastLoginAt: this.LastLoginAt,
2791
2807
  MFAEnabled: this.MFAEnabled,
2792
2808
  MFAConfig: this.MFAConfig,
2809
+ MFABypassYN: this.MFABypassYN,
2793
2810
  RecoveryEmail: this.RecoveryEmail,
2794
2811
  FailedLoginAttemptCount: this.FailedLoginAttemptCount,
2795
2812
  LastFailedLoginAt: this.LastFailedLoginAt,
@@ -2821,6 +2838,7 @@ export class User extends UserBase {
2821
2838
  LastLoginAt: this.LastLoginAt,
2822
2839
  MFAEnabled: this.MFAEnabled,
2823
2840
  MFAConfig: this.MFAConfig,
2841
+ MFABypassYN: this.MFABypassYN,
2824
2842
  RecoveryEmail: this.RecoveryEmail,
2825
2843
  FailedLoginAttemptCount: this.FailedLoginAttemptCount,
2826
2844
  LastFailedLoginAt: this.LastFailedLoginAt,
@@ -2911,6 +2929,7 @@ export class User extends UserBase {
2911
2929
  LastLoginAt: this.LastLoginAt,
2912
2930
  MFAEnabled: this.MFAEnabled,
2913
2931
  MFAConfig: this.MFAConfig,
2932
+ MFABypassYN: this.MFABypassYN,
2914
2933
  RecoveryEmail: this.RecoveryEmail,
2915
2934
  FailedLoginAttemptCount: this.FailedLoginAttemptCount,
2916
2935
  LastFailedLoginAt: this.LastFailedLoginAt,
@@ -2942,6 +2961,7 @@ export class User extends UserBase {
2942
2961
  LastLoginAt: this.LastLoginAt,
2943
2962
  MFAEnabled: this.MFAEnabled,
2944
2963
  MFAConfig: this.MFAConfig,
2964
+ MFABypassYN: this.MFABypassYN,
2945
2965
  RecoveryEmail: this.RecoveryEmail,
2946
2966
  FailedLoginAttemptCount: this.FailedLoginAttemptCount,
2947
2967
  LastFailedLoginAt: this.LastFailedLoginAt,
@@ -3131,4 +3151,244 @@ export class User extends UserBase {
3131
3151
  throw error;
3132
3152
  }
3133
3153
  }
3154
+
3155
+ public async enable2FABypass(loginUser: LoginUser, dbTransaction: any) {
3156
+ try {
3157
+ // 1. Check if MFABypassYN is already enabled
3158
+ if (this.MFABypassYN === YN.Yes) {
3159
+ throw new ClassError(
3160
+ 'User',
3161
+ 'UserErrMsg0X',
3162
+ 'Bypass already enabled.',
3163
+ 'enable2FABypass',
3164
+ );
3165
+ }
3166
+
3167
+ // 2. Check if user has MANAGE_MFA privilege
3168
+ const systemCode =
3169
+ ApplicationConfig.getComponentConfigValue('system-code');
3170
+ const isPrivileged = await loginUser.checkPrivileges(
3171
+ systemCode,
3172
+ 'MANAGE_MFA',
3173
+ );
3174
+ if (!isPrivileged) {
3175
+ throw new ClassError(
3176
+ 'LoginUser',
3177
+ 'LoginUserErrMsg0X',
3178
+ 'You do not have permission to enable MFA bypass.',
3179
+ );
3180
+ }
3181
+
3182
+ const entityValueBefore: IUserAttr = {
3183
+ UserId: this.UserId,
3184
+ UserName: this.UserName,
3185
+ FullName: this.FullName,
3186
+ IDNo: this.IDNo,
3187
+ IDType: this.IDType,
3188
+ ContactNo: this.ContactNo,
3189
+ Email: this.Email,
3190
+ Password: this.Password,
3191
+ Status: this.Status,
3192
+ DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
3193
+ FirstLoginAt: this.FirstLoginAt,
3194
+ LastLoginAt: this.LastLoginAt,
3195
+ MFAEnabled: this.MFAEnabled,
3196
+ MFAConfig: this.MFAConfig,
3197
+ MFABypassYN: this.MFABypassYN,
3198
+ RecoveryEmail: this.RecoveryEmail,
3199
+ FailedLoginAttemptCount: this.FailedLoginAttemptCount,
3200
+ LastFailedLoginAt: this.LastFailedLoginAt,
3201
+ LastPasswordChangedAt: this.LastPasswordChangedAt,
3202
+ NeedToChangePasswordYN: this.NeedToChangePasswordYN,
3203
+ CreatedById: this.CreatedById,
3204
+ CreatedAt: this.CreatedAt,
3205
+ UpdatedById: this.UpdatedById,
3206
+ UpdatedAt: this.UpdatedAt,
3207
+ PasscodeHash: this.PasscodeHash,
3208
+ PasscodeUpdatedAt: this.PasscodeUpdatedAt,
3209
+ };
3210
+
3211
+ // 3. Update user record
3212
+ this.MFABypassYN = YN.Yes;
3213
+ this.UpdatedAt = new Date();
3214
+ this.UpdatedById = loginUser.UserId;
3215
+
3216
+ await User._Repository.update(
3217
+ {
3218
+ MFABypassYN: this.MFABypassYN,
3219
+ UpdatedAt: this.UpdatedAt,
3220
+ UpdatedById: this.UpdatedById,
3221
+ },
3222
+ {
3223
+ where: {
3224
+ UserId: this.UserId,
3225
+ },
3226
+ transaction: dbTransaction,
3227
+ },
3228
+ );
3229
+
3230
+ const entityValueAfter: IUserAttr = {
3231
+ UserId: this.UserId,
3232
+ UserName: this.UserName,
3233
+ FullName: this.FullName,
3234
+ IDNo: this.IDNo,
3235
+ IDType: this.IDType,
3236
+ ContactNo: this.ContactNo,
3237
+ Email: this.Email,
3238
+ Password: this.Password,
3239
+ Status: this.Status,
3240
+ DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
3241
+ FirstLoginAt: this.FirstLoginAt,
3242
+ LastLoginAt: this.LastLoginAt,
3243
+ MFAEnabled: this.MFAEnabled,
3244
+ MFAConfig: this.MFAConfig,
3245
+ MFABypassYN: this.MFABypassYN,
3246
+ RecoveryEmail: this.RecoveryEmail,
3247
+ FailedLoginAttemptCount: this.FailedLoginAttemptCount,
3248
+ LastFailedLoginAt: this.LastFailedLoginAt,
3249
+ LastPasswordChangedAt: this.LastPasswordChangedAt,
3250
+ NeedToChangePasswordYN: this.NeedToChangePasswordYN,
3251
+ CreatedById: this.CreatedById,
3252
+ CreatedAt: this.CreatedAt,
3253
+ UpdatedById: this.UpdatedById,
3254
+ UpdatedAt: this.UpdatedAt,
3255
+ PasscodeHash: this.PasscodeHash,
3256
+ PasscodeUpdatedAt: this.PasscodeUpdatedAt,
3257
+ };
3258
+
3259
+ // Record update activity using Activity class create method.
3260
+ const activity = new Activity();
3261
+ activity.ActivityId = activity.createId();
3262
+ activity.Action = ActionEnum.UPDATE;
3263
+ activity.Description = `Enable 2FA Bypass For User ${this.Email}`;
3264
+ activity.EntityType = this.ObjectType;
3265
+ activity.EntityId = this.UserId.toString();
3266
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
3267
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
3268
+
3269
+ await activity.create(loginUser.ObjectId, dbTransaction);
3270
+ } catch (error) {
3271
+ throw error;
3272
+ }
3273
+ }
3274
+
3275
+ public async disable2FABypass(loginUser: LoginUser, dbTransaction: any) {
3276
+ try {
3277
+ // 1. Check if MFABypassYN is already disabled
3278
+ if (this.MFABypassYN === YN.No) {
3279
+ throw new ClassError(
3280
+ 'User',
3281
+ 'UserErrMsg0X',
3282
+ 'Bypass already disabled.',
3283
+ 'disable2FABypass',
3284
+ );
3285
+ }
3286
+
3287
+ // 2. Check if user has MANAGE_MFA privilege
3288
+ const systemCode =
3289
+ ApplicationConfig.getComponentConfigValue('system-code');
3290
+ const isPrivileged = await loginUser.checkPrivileges(
3291
+ systemCode,
3292
+ 'MANAGE_MFA',
3293
+ );
3294
+ if (!isPrivileged) {
3295
+ throw new ClassError(
3296
+ 'LoginUser',
3297
+ 'LoginUserErrMsg0X',
3298
+ 'You do not have permission to enable MFA bypass.',
3299
+ );
3300
+ }
3301
+
3302
+ const entityValueBefore: IUserAttr = {
3303
+ UserId: this.UserId,
3304
+ UserName: this.UserName,
3305
+ FullName: this.FullName,
3306
+ IDNo: this.IDNo,
3307
+ IDType: this.IDType,
3308
+ ContactNo: this.ContactNo,
3309
+ Email: this.Email,
3310
+ Password: this.Password,
3311
+ Status: this.Status,
3312
+ DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
3313
+ FirstLoginAt: this.FirstLoginAt,
3314
+ LastLoginAt: this.LastLoginAt,
3315
+ MFAEnabled: this.MFAEnabled,
3316
+ MFAConfig: this.MFAConfig,
3317
+ MFABypassYN: this.MFABypassYN,
3318
+ RecoveryEmail: this.RecoveryEmail,
3319
+ FailedLoginAttemptCount: this.FailedLoginAttemptCount,
3320
+ LastFailedLoginAt: this.LastFailedLoginAt,
3321
+ LastPasswordChangedAt: this.LastPasswordChangedAt,
3322
+ NeedToChangePasswordYN: this.NeedToChangePasswordYN,
3323
+ CreatedById: this.CreatedById,
3324
+ CreatedAt: this.CreatedAt,
3325
+ UpdatedById: this.UpdatedById,
3326
+ UpdatedAt: this.UpdatedAt,
3327
+ PasscodeHash: this.PasscodeHash,
3328
+ PasscodeUpdatedAt: this.PasscodeUpdatedAt,
3329
+ };
3330
+
3331
+ // 3. Update user record
3332
+ this.MFABypassYN = YN.No;
3333
+ this.UpdatedAt = new Date();
3334
+ this.UpdatedById = loginUser.UserId;
3335
+
3336
+ await User._Repository.update(
3337
+ {
3338
+ MFABypassYN: this.MFABypassYN,
3339
+ UpdatedAt: this.UpdatedAt,
3340
+ UpdatedById: this.UpdatedById,
3341
+ },
3342
+ {
3343
+ where: {
3344
+ UserId: this.UserId,
3345
+ },
3346
+ transaction: dbTransaction,
3347
+ },
3348
+ );
3349
+
3350
+ const entityValueAfter: IUserAttr = {
3351
+ UserId: this.UserId,
3352
+ UserName: this.UserName,
3353
+ FullName: this.FullName,
3354
+ IDNo: this.IDNo,
3355
+ IDType: this.IDType,
3356
+ ContactNo: this.ContactNo,
3357
+ Email: this.Email,
3358
+ Password: this.Password,
3359
+ Status: this.Status,
3360
+ DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
3361
+ FirstLoginAt: this.FirstLoginAt,
3362
+ LastLoginAt: this.LastLoginAt,
3363
+ MFAEnabled: this.MFAEnabled,
3364
+ MFAConfig: this.MFAConfig,
3365
+ MFABypassYN: this.MFABypassYN,
3366
+ RecoveryEmail: this.RecoveryEmail,
3367
+ FailedLoginAttemptCount: this.FailedLoginAttemptCount,
3368
+ LastFailedLoginAt: this.LastFailedLoginAt,
3369
+ LastPasswordChangedAt: this.LastPasswordChangedAt,
3370
+ NeedToChangePasswordYN: this.NeedToChangePasswordYN,
3371
+ CreatedById: this.CreatedById,
3372
+ CreatedAt: this.CreatedAt,
3373
+ UpdatedById: this.UpdatedById,
3374
+ UpdatedAt: this.UpdatedAt,
3375
+ PasscodeHash: this.PasscodeHash,
3376
+ PasscodeUpdatedAt: this.PasscodeUpdatedAt,
3377
+ };
3378
+
3379
+ // Record update activity using Activity class create method.
3380
+ const activity = new Activity();
3381
+ activity.ActivityId = activity.createId();
3382
+ activity.Action = ActionEnum.UPDATE;
3383
+ activity.Description = `Disable 2FA Bypass For User ${this.Email}`;
3384
+ activity.EntityType = this.ObjectType;
3385
+ activity.EntityId = this.UserId.toString();
3386
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
3387
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
3388
+
3389
+ await activity.create(loginUser.ObjectId, dbTransaction);
3390
+ } catch (error) {
3391
+ throw error;
3392
+ }
3393
+ }
3134
3394
  }
@@ -88,6 +88,13 @@ export default class User extends Model {
88
88
  })
89
89
  DefaultPasswordChangedYN: YN;
90
90
 
91
+ @Column({
92
+ allowNull: true,
93
+ type: DataType.CHAR(1),
94
+ defaultValue: 'N',
95
+ })
96
+ MFABypassYN: YN;
97
+
91
98
  @Column({
92
99
  type: DataType.DATE,
93
100
  })
@@ -1,23 +0,0 @@
1
- sonar.projectKey=all-tomei-projects_sso
2
- sonar.organization=all-tomei-projects
3
- sonar.exclusions=**/*.js,test-data,dist,coverage, node_modules, __tests__, **/*.spec.ts, __mocks__
4
- sonar.scm.provider=git
5
-
6
- sonar.sources=src
7
- sonar.test=__tests__
8
- sonar.test.inclusions=src/**/*.spec.ts
9
-
10
- sonar.javascript.lcov.reportPaths=./coverage/lcov.info
11
- sonar.testExecutionReportPaths=coverage/test-report.xml
12
- sonar.sourceEnconding=UTF-8
13
-
14
- # This is the name and version displayed in the SonarCloud UI.
15
- #sonar.projectName=sso
16
- #sonar.projectVersion=1.0
17
-
18
-
19
- # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
20
- #sonar.sources=.
21
-
22
- # Encoding of the source code. Default is default system encoding
23
- #sonar.sourceEncoding=UTF-8