@solidstarters/solid-core 1.2.168 → 1.2.170

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/dtos/create-ai-interaction.dto.d.ts +3 -0
  2. package/dist/dtos/create-ai-interaction.dto.d.ts.map +1 -1
  3. package/dist/dtos/create-ai-interaction.dto.js +19 -1
  4. package/dist/dtos/create-ai-interaction.dto.js.map +1 -1
  5. package/dist/dtos/update-ai-interaction.dto.d.ts +3 -0
  6. package/dist/dtos/update-ai-interaction.dto.d.ts.map +1 -1
  7. package/dist/dtos/update-ai-interaction.dto.js +19 -1
  8. package/dist/dtos/update-ai-interaction.dto.js.map +1 -1
  9. package/dist/entities/ai-interaction.entity.d.ts +3 -0
  10. package/dist/entities/ai-interaction.entity.d.ts.map +1 -1
  11. package/dist/entities/ai-interaction.entity.js +13 -1
  12. package/dist/entities/ai-interaction.entity.js.map +1 -1
  13. package/dist/filters/http-exception.filter.d.ts.map +1 -1
  14. package/dist/filters/http-exception.filter.js +2 -1
  15. package/dist/filters/http-exception.filter.js.map +1 -1
  16. package/dist/helpers/error-mapper.service.d.ts.map +1 -1
  17. package/dist/helpers/error-mapper.service.js +1 -1
  18. package/dist/helpers/error-mapper.service.js.map +1 -1
  19. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  20. package/dist/helpers/solid-core-error-codes-provider.service.js +3 -3
  21. package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -1
  22. package/dist/helpers/solid-registry.d.ts +0 -1
  23. package/dist/helpers/solid-registry.d.ts.map +1 -1
  24. package/dist/helpers/solid-registry.js +0 -1
  25. package/dist/helpers/solid-registry.js.map +1 -1
  26. package/dist/index.d.ts +0 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +0 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +2 -2
  31. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  32. package/dist/seeders/seed-data/solid-core-metadata.json +33 -0
  33. package/dist/services/authentication.service.d.ts +1 -5
  34. package/dist/services/authentication.service.d.ts.map +1 -1
  35. package/dist/services/authentication.service.js +22 -64
  36. package/dist/services/authentication.service.js.map +1 -1
  37. package/dist/services/export-transaction.service.d.ts +3 -1
  38. package/dist/services/export-transaction.service.d.ts.map +1 -1
  39. package/dist/services/export-transaction.service.js +70 -16
  40. package/dist/services/export-transaction.service.js.map +1 -1
  41. package/dist/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.js +1 -1
  42. package/dist/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.js.map +1 -1
  43. package/dist/solid-core.module.d.ts.map +1 -1
  44. package/dist/solid-core.module.js +0 -2
  45. package/dist/solid-core.module.js.map +1 -1
  46. package/dist/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +1 -1
  48. package/src/dtos/create-ai-interaction.dto.ts +15 -0
  49. package/src/dtos/update-ai-interaction.dto.ts +15 -0
  50. package/src/entities/ai-interaction.entity.ts +9 -0
  51. package/src/filters/http-exception.filter.ts +5 -2
  52. package/src/helpers/error-mapper.service.ts +1 -35
  53. package/src/helpers/model-metadata-helper.service.ts +1 -1
  54. package/src/helpers/solid-core-error-codes-provider.service.ts +4 -4
  55. package/src/helpers/solid-registry.ts +0 -1
  56. package/src/index.ts +0 -1
  57. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +2 -2
  58. package/src/seeders/seed-data/solid-core-metadata.json +35 -2
  59. package/src/services/authentication.service.ts +31 -142
  60. package/src/services/export-transaction.service.ts +118 -55
  61. package/src/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.ts +1 -1
  62. package/src/solid-core.module.ts +0 -8
  63. package/dist/entities/user-password-history.entity.d.ts +0 -7
  64. package/dist/entities/user-password-history.entity.d.ts.map +0 -1
  65. package/dist/entities/user-password-history.entity.js +0 -35
  66. package/dist/entities/user-password-history.entity.js.map +0 -1
  67. package/src/entities/user-password-history.entity.ts +0 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.168",
3
+ "version": "1.2.170",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -64,4 +64,19 @@ export class CreateAiInteractionDto {
64
64
  @IsBoolean()
65
65
  @ApiProperty()
66
66
  isAutoApply: boolean = false;
67
+
68
+ @IsOptional()
69
+ @IsInt()
70
+ @ApiProperty()
71
+ inputTokens: number;
72
+
73
+ @IsOptional()
74
+ @IsInt()
75
+ @ApiProperty()
76
+ outputTokens: number;
77
+
78
+ @IsOptional()
79
+ @IsInt()
80
+ @ApiProperty()
81
+ totalTokens: number;
67
82
  }
@@ -68,4 +68,19 @@ export class UpdateAiInteractionDto {
68
68
  @IsBoolean()
69
69
  @ApiProperty()
70
70
  isAutoApply: boolean;
71
+
72
+ @IsOptional()
73
+ @IsInt()
74
+ @ApiProperty()
75
+ inputTokens: number;
76
+
77
+ @IsOptional()
78
+ @IsInt()
79
+ @ApiProperty()
80
+ outputTokens: number;
81
+
82
+ @IsOptional()
83
+ @IsInt()
84
+ @ApiProperty()
85
+ totalTokens: number;
71
86
  }
@@ -39,4 +39,13 @@ export class AiInteraction extends CommonEntity {
39
39
  externalId: string;
40
40
  @Column({ type: "boolean", nullable: true, default: false })
41
41
  isAutoApply: boolean = false;
42
+
43
+ @Column({ type: "integer", nullable: true })
44
+ inputTokens: number;
45
+
46
+ @Column({ type: "integer", nullable: true })
47
+ outputTokens: number;
48
+
49
+ @Column({ type: "integer", nullable: true })
50
+ totalTokens: number;
42
51
  }
@@ -33,7 +33,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
33
33
  // Canonical code + static message
34
34
  const code: ErrorCode = this.errorMapper.mapException(exception);
35
35
  const defaultStatus = this.errorMapper.getHttpStatus(code);
36
- const message = this.errorMapper.getMessage(code);
36
+ const message = code === 'solidx-unknown-error' ? `${exception?.message}` : this.errorMapper.getMessage(code);
37
37
 
38
38
  const status = explicitStatus ?? defaultStatus ?? 500;
39
39
 
@@ -55,9 +55,12 @@ export class HttpExceptionFilter implements ExceptionFilter {
55
55
  response.status(status).json({
56
56
  statusCode: status,
57
57
  statusCodeMessage: HttpStatusCodeMessages[status] || 'Internal Server Error',
58
- // message: [message],
58
+ // Keeping this for backward compatibility..
59
+ message: message,
59
60
  errorCode: code,
60
61
  error: message,
62
+ // We can make this conditional based on whether we are running in prod mode or dev mode...
63
+ // errorStack: exception.stack,
61
64
  data: extra,
62
65
  });
63
66
  }
@@ -1,40 +1,6 @@
1
1
  import { Injectable, Logger } from '@nestjs/common';
2
2
  import { SolidRegistry } from 'src/helpers/solid-registry';
3
3
  import { ErrorCode, ErrorMeta, ErrorRule, IErrorCodeProvider } from 'src/interfaces';
4
-
5
- // export const ERROR_CODES = [
6
- // 'db-duplicate-key',
7
- // 'db-foreign-key-error',
8
- // 'solidx-mcp-server-unavailable',
9
- // 'unknown-error',
10
- // ] as const;
11
-
12
- // export type ErrorCode = typeof ERROR_CODES[number];
13
-
14
- // type ErrorMeta = {
15
- // message: string;
16
- // httpStatus?: number;
17
- // };
18
-
19
- // const ERROR_MESSAGES: Record<ErrorCode, ErrorMeta> = {
20
- // 'db-duplicate-key': {
21
- // message: 'Duplicate key violation. A record with these values already exists.',
22
- // httpStatus: 409,
23
- // },
24
- // 'db-foreign-key-error': {
25
- // message: 'Foreign key constraint prevents this operation due to related records.',
26
- // httpStatus: 409,
27
- // },
28
- // 'solidx-mcp-server-unavailable': {
29
- // message: 'SolidX MCP server is unreachable. Please verify the MCP endpoint.',
30
- // httpStatus: 503,
31
- // },
32
- // 'unknown-error': {
33
- // message: 'An unexpected error occurred.',
34
- // httpStatus: 500,
35
- // },
36
- // };
37
-
38
4
  @Injectable()
39
5
  export class ErrorMapperService {
40
6
  private readonly logger = new Logger(ErrorMapperService.name);
@@ -76,7 +42,7 @@ export class ErrorMapperService {
76
42
  this.logger.warn(`Error rule threw in match(): code=${rule.code} provider? — ${e}`);
77
43
  }
78
44
  }
79
- return 'unknown-error';
45
+ return 'solidx-unknown-error';
80
46
  }
81
47
 
82
48
  private lookupMeta(code: ErrorCode): ErrorMeta | undefined {
@@ -122,7 +122,7 @@ export class ModelMetadataHelperService {
122
122
  }
123
123
  }
124
124
  });
125
- const fields = [];
125
+ const fields: any[] = [];
126
126
  if (model) {
127
127
  // Add the fields of the current model
128
128
  fields.push(...model.fields);
@@ -15,7 +15,7 @@ export class SolidCoreErrorCodesProvider implements IErrorCodeProvider {
15
15
  return [
16
16
  {
17
17
  code: 'solidx-mcp-server-unavailable',
18
- priority: 100, // run early
18
+ priority: 100,
19
19
  match: (txt) =>
20
20
  txt.includes('all connection attempts failed') &&
21
21
  txt.includes('unhandled errors in a taskgroup (1 sub-exception)'),
@@ -25,7 +25,7 @@ export class SolidCoreErrorCodesProvider implements IErrorCodeProvider {
25
25
  },
26
26
  },
27
27
  {
28
- code: 'db-duplicate-key',
28
+ code: 'solidx-db-duplicate-key',
29
29
  priority: 90,
30
30
  match: (txt) => txt.includes('unique constraint') || txt.includes('duplicate key'),
31
31
  meta: {
@@ -34,7 +34,7 @@ export class SolidCoreErrorCodesProvider implements IErrorCodeProvider {
34
34
  },
35
35
  },
36
36
  {
37
- code: 'db-foreign-key-error',
37
+ code: 'solidx-db-foreign-key-error',
38
38
  priority: 90,
39
39
  match: (txt) => txt.includes('violates foreign key'),
40
40
  meta: {
@@ -44,7 +44,7 @@ export class SolidCoreErrorCodesProvider implements IErrorCodeProvider {
44
44
  },
45
45
  },
46
46
  {
47
- code: 'unknown-error',
47
+ code: 'solidx-unknown-error',
48
48
  priority: -1, // last resort
49
49
  match: (_txt) => true, // fallback catch-all
50
50
  meta: {
@@ -33,7 +33,6 @@ export enum RESERVED_SOLID_KEYWORDS {
33
33
  securityRule = "securityRule",
34
34
  setting = "setting",
35
35
  smsTemplate = "smsTemplate",
36
- userPasswordHistory = "userPasswordHistory",
37
36
  userMetadata = "userMetadata",
38
37
  user = "user",
39
38
  locale = "locale"
package/src/index.ts CHANGED
@@ -112,7 +112,6 @@ export * from './entities/scheduled-job.entity'
112
112
  export * from './entities/permission-metadata.entity'
113
113
  export * from './entities/role-metadata.entity'
114
114
  export * from './entities/sms-template.entity'
115
- export * from './entities/user-password-history.entity'
116
115
  export * from './entities/user.entity'
117
116
  export * from './entities/view-metadata.entity'
118
117
  export * from './entities/setting.entity'
@@ -67,7 +67,7 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
67
67
  errorMessage: errorsStr,
68
68
  modelUsed: aiResponse.model,
69
69
  responseTimeMs: aiResponse.duration_ms,
70
- metadata: JSON.stringify(aiResponse),
70
+ metadata: JSON.stringify(aiResponse, null, 2),
71
71
  isApplied: aiInteraction.isApplied,
72
72
  status: aiResponse.success ? 'succeeded' : 'failed'
73
73
  });
@@ -88,7 +88,7 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
88
88
  errorMessage: '',
89
89
  modelUsed: aiResponse.model,
90
90
  responseTimeMs: aiResponse.duration_ms,
91
- metadata: JSON.stringify(aiResponse),
91
+ metadata: JSON.stringify(aiResponse, null, 2),
92
92
  isApplied: aiInteraction.isApplied,
93
93
  status: aiResponse.success ? 'succeeded' : 'failed'
94
94
  });
@@ -5152,6 +5152,39 @@
5152
5152
  "index": false,
5153
5153
  "private": false,
5154
5154
  "encrypt": false
5155
+ },
5156
+ {
5157
+ "name": "inputTokens",
5158
+ "displayName": "Input Tokens",
5159
+ "type": "int",
5160
+ "ormType": "integer",
5161
+ "required": false,
5162
+ "unique": false,
5163
+ "index": false,
5164
+ "private": false,
5165
+ "encrypt": false
5166
+ },
5167
+ {
5168
+ "name": "outputTokens",
5169
+ "displayName": "Output Tokens",
5170
+ "type": "int",
5171
+ "ormType": "integer",
5172
+ "required": false,
5173
+ "unique": false,
5174
+ "index": false,
5175
+ "private": false,
5176
+ "encrypt": false
5177
+ },
5178
+ {
5179
+ "name": "totalTokens",
5180
+ "displayName": "Total Tokens",
5181
+ "type": "int",
5182
+ "ormType": "integer",
5183
+ "required": false,
5184
+ "unique": false,
5185
+ "index": false,
5186
+ "private": false,
5187
+ "encrypt": false
5155
5188
  }
5156
5189
  ]
5157
5190
  }
@@ -5584,7 +5617,7 @@
5584
5617
  "moduleUserKey": "solid-core",
5585
5618
  "modelUserKey": "setting"
5586
5619
  },
5587
- {
5620
+ {
5588
5621
  "displayName": "Ai settings",
5589
5622
  "name": "ai-settings-action",
5590
5623
  "type": "custom",
@@ -5965,7 +5998,7 @@
5965
5998
  "moduleUserKey": "solid-core",
5966
5999
  "parentMenuItemUserKey": "settings-menu-item"
5967
6000
  },
5968
- {
6001
+ {
5969
6002
  "displayName": "Ai Settings",
5970
6003
  "name": "ai-settings-menu-item",
5971
6004
  "sequenceNumber": 3,
@@ -28,7 +28,6 @@ import { OTPSignUpDto } from '../dtos/otp-sign-up.dto';
28
28
  import { RefreshTokenDto } from '../dtos/refresh-token.dto';
29
29
  import { SignInDto } from '../dtos/sign-in.dto';
30
30
  import { SignUpDto } from '../dtos/sign-up.dto';
31
- import { UserPasswordHistory } from '../entities/user-password-history.entity';
32
31
  import { User } from '../entities/user.entity';
33
32
  import { ActiveUserData } from '../interfaces/active-user-data.interface';
34
33
  import { HashingService } from './hashing.service';
@@ -69,7 +68,6 @@ export class AuthenticationService {
69
68
  constructor(
70
69
  private readonly userService: UserService,
71
70
  @InjectRepository(User) private readonly userRepository: Repository<User>,
72
- @InjectRepository(UserPasswordHistory) private readonly userPasswordHistoryRepository: Repository<UserPasswordHistory>,
73
71
  private readonly hashingService: HashingService,
74
72
  private readonly jwtService: JwtService,
75
73
  @Inject(jwtConfig.KEY)
@@ -210,22 +208,39 @@ export class AuthenticationService {
210
208
  if (signUpDto.mobile) {
211
209
  user.mobile = signUpDto.mobile;
212
210
  }
213
- this.logger.debug("user", user);
211
+ // this.logger.debug("user", user);
212
+
214
213
  // If password has been specified by the user, then we simply create & activate the user based on the configuration parameter "activateUserOnRegistration".
215
214
  let pwd = '';
216
215
  let autoGeneratedPwd = '';
216
+
217
+ // User has specified password
217
218
  if (signUpDto.password) {
218
219
  pwd = await this.hashingService.hash(signUpDto.password);
219
220
  }
220
- if(autoGeneratedPwdPermission?.toString().toLowerCase() === 'true'){
221
- // TODO: If password is not specified then auto-generate a random password, trigger this password over an email to the user.
222
- // TODO: Also track if the user has to force reset / change their password, and then activate the user.
223
- autoGeneratedPwd = this.generatePassword();
224
- pwd = await this.hashingService.hash(autoGeneratedPwd);
225
- user.forcePasswordChange = true;
221
+ // User has not specified password
222
+ else {
223
+ // When user does not specify password, and system is configured to auto generate passwords.
224
+ if (autoGeneratedPwdPermission?.toString().toLowerCase() === 'true') {
225
+ autoGeneratedPwd = this.generatePassword();
226
+ pwd = await this.hashingService.hash(autoGeneratedPwd);
227
+ user.forcePasswordChange = true;
228
+ }
229
+ // When user does not specify password, and system is not configured to auto generate passwords.
230
+ else {
231
+ // This means that most likely the system is going to be using password-less login.
232
+ // If that is not the case then we can raise a bad request exception...
233
+ if (!this.isPasswordlessRegistrationEnabled()) {
234
+ this.logger.error('User being created without password, and password less login is also not enabled in the system. Is this intentional?');
235
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
236
+ }
237
+
238
+ // Save the hash of the blank password, anyways since passwordless login is enabled it does not matter.
239
+ pwd = await this.hashingService.hash(pwd);
240
+ }
226
241
  }
242
+
227
243
  user.password = pwd;
228
- // user.active = this.iamConfiguration.activateUserOnRegistration;
229
244
  user.active = isUserActive;
230
245
  return { user, pwd, autoGeneratedPwd };
231
246
  }
@@ -233,11 +248,6 @@ export class AuthenticationService {
233
248
 
234
249
  private async handlePostSignup(user: User, roles: string[] = [], pwd: string, autoGeneratedPwd: string) {
235
250
  await this.userService.initializeRolesForNewUser(roles, user);
236
- // Tanay: Adding user password to history table
237
- const userPasswordHistory = new UserPasswordHistory();
238
- userPasswordHistory.passwordHash = pwd;
239
- userPasswordHistory.user = user;
240
- await this.userPasswordHistoryRepository.save(userPasswordHistory);
241
251
 
242
252
  // if forcePasswordChange is true, then we trigger an email to the user to change the password, this needs to be done using a queue.
243
253
  // Create a new method like notifyUserOnForcePasswordChange, create a new email template we can call it on-force-password-change this template to include the random password
@@ -524,7 +534,7 @@ export class AuthenticationService {
524
534
  username: user.username,
525
535
  forcePasswordChange: user.forcePasswordChange,
526
536
  id: user.id,
527
- roles: user.roles.map((role, idx, roles) => role.name)
537
+ roles: user.roles.map((role) => role.name)
528
538
  },
529
539
  ...tokens
530
540
  }
@@ -721,19 +731,9 @@ export class AuthenticationService {
721
731
 
722
732
  // Everytime the user changes the password we reset the forcePasswordChange flag back to false.
723
733
  user.forcePasswordChange = false;
724
-
725
- if (await this.isPasswordDuplicate(user)) {
726
- throw new BadRequestException(ERROR_MESSAGES.PASSWORD_REUSED);
727
- }
728
- await this.deleteOldPasswords(user);
729
-
730
734
  user.password = newPwd;
731
- const userPasswordHistory = new UserPasswordHistory();
732
- userPasswordHistory.passwordHash = newPwd;
733
- userPasswordHistory.user = user;
734
735
 
735
736
  await this.userRepository.save(user);
736
- await this.userPasswordHistoryRepository.save(userPasswordHistory);
737
737
 
738
738
  return true;
739
739
  }
@@ -761,7 +761,7 @@ export class AuthenticationService {
761
761
 
762
762
  let isValidUser = true // Instead of throwing exceptions we will simply return success message, this is to avoid user enumeration attacks.
763
763
  if (!user) {
764
- isValidUser = false
764
+ isValidUser = false
765
765
  // throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
766
766
  }
767
767
  if (isValidUser && !user?.active) {
@@ -792,7 +792,7 @@ export class AuthenticationService {
792
792
  error: '',
793
793
  errorCode: '',
794
794
  data: {
795
- user: {
795
+ user: {
796
796
  email: user?.email,
797
797
  // mobile: user.mobile,
798
798
  // username: user.username,
@@ -873,24 +873,8 @@ export class AuthenticationService {
873
873
  // 2) Now update the password & history (still inside the same transaction)
874
874
  const pwdHash = await this.hashingService.hash(confirmForgotPasswordDto.password);
875
875
 
876
- // Avoid ever assigning plaintext:
877
- // user.password = dto.password <-- remove this line in your original code
878
-
879
876
  // Check reuse with your existing method (ensure it looks at hashes).
880
- const tempUser = { ...user, password: pwdHash } as User; // if your helper expects it
881
- if (await this.isPasswordDuplicate(tempUser)) {
882
- throw new BadRequestException(ERROR_MESSAGES.PASSWORD_REUSED);
883
- }
884
-
885
- await this.deleteOldPasswords(user);
886
-
887
877
  await m.getRepository(User).update({ id: user.id }, { password: pwdHash });
888
-
889
- const history = m.getRepository(UserPasswordHistory).create({
890
- user: { id: user.id } as any,
891
- passwordHash: pwdHash,
892
- });
893
- await m.getRepository(UserPasswordHistory).save(history);
894
878
  this.notifyUserOnPasswordChanged(user);
895
879
 
896
880
  return {
@@ -946,101 +930,6 @@ export class AuthenticationService {
946
930
  }
947
931
  }
948
932
 
949
- // async confirmForgotPassword(confirmForgotPasswordDto: ConfirmForgotPasswordDto) {
950
- // // Steps / Algorithm:
951
- // // 1. Identify the user using the specified "username", if not found exit.
952
- // // const user = await this.userRepository.findOne({
953
- // // where: { username: confirmForgotPasswordDto.username, }
954
- // // });
955
- // const user = await this.resolveUserByVerificationToken(confirmForgotPasswordDto.verificationToken);
956
-
957
- // if (!user) {
958
- // throw new NotFoundException(ERROR_MESSAGES.USER_NOT_FOUND);
959
- // }
960
-
961
- // // 2. Validate if user has used a provider which is "local", only then it makes sense for us to initiate the forgot password routine.
962
- // if (user.lastLoginProvider !== 'local') {
963
- // throw new BadRequestException(ERROR_MESSAGES.NON_LOCAL_PROVIDER);
964
- // }
965
- // if (!user.active) {
966
- // throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
967
- // }
968
-
969
- // // 3. Validate the verification token is proper & update the user record.
970
- // if (user.verificationTokenOnForgotPassword !== confirmForgotPasswordDto.verificationToken) {
971
- // throw new UnauthorizedException(ERROR_MESSAGES.INVALID_VERIFICATION_TOKEN);
972
- // }
973
- // if (user.verificationTokenOnForgotPasswordExpiresAt < new Date()) {
974
- // throw new UnauthorizedException(ERROR_MESSAGES.INVALID_VERIFICATION_TOKEN);
975
- // }
976
- // user.forgotPasswordConfirmedAt = new Date();
977
- // user.verificationTokenOnForgotPassword = null;
978
- // user.verificationTokenOnForgotPasswordExpiresAt = null;
979
-
980
- // // 4. Update the users password while encrypting it.
981
- // const pwd = await this.hashingService.hash(confirmForgotPasswordDto.password);
982
- // user.password = confirmForgotPasswordDto.password
983
-
984
- // if (await this.isPasswordDuplicate(user)) {
985
- // throw new BadRequestException(ERROR_MESSAGES.PASSWORD_REUSED);
986
- // }
987
- // await this.deleteOldPasswords(user);
988
-
989
- // user.password = pwd;
990
- // const userPasswordHistory = new UserPasswordHistory();
991
- // userPasswordHistory.passwordHash = pwd;
992
- // userPasswordHistory.user = user;
993
-
994
- // await this.userRepository.save(user);
995
- // //FIXME: Do this check conditionally, basis a configuration parameter i.e if IAM_ALLOW_PREVIOUS_PASSWORDS=false, default true
996
- // await this.userPasswordHistoryRepository.save(userPasswordHistory);
997
-
998
- // return {
999
- // status: 'success',
1000
- // message: SUCCESS_MESSAGES.FORGOT_PASSWORD_CONFIRMED,
1001
- // error: '',
1002
- // errorCode: '',
1003
- // data: {}
1004
- // }
1005
- // }
1006
-
1007
- //FIXME: Do this check conditionally, basis a configuration parameter i.e if IAM_ALLOW_PREVIOUS_PASSWORDS=true, return immediately without processing, i.e false.
1008
- private async isPasswordDuplicate(user: User) {
1009
- const userPwdHistoryEntityArray = await this.userPasswordHistoryRepository.findBy(
1010
- { user: { id: user.id } }
1011
- )
1012
- let userPwdHistoryArray = [];
1013
- // O(n)
1014
- for (const entity of userPwdHistoryEntityArray) {
1015
- userPwdHistoryArray.push(entity.passwordHash);
1016
- }
1017
- // O(n)
1018
- for (const pwdHash of userPwdHistoryArray) {
1019
- const isEqual = await this.hashingService.compare(user.password, pwdHash);
1020
- if (isEqual) {
1021
- return true;
1022
- }
1023
- }
1024
- return false;
1025
- }
1026
-
1027
- //FIXME: Do this check conditionally, basis a configuration parameter i.e if IAM_ALLOW_PREVIOUS_PASSWORDS=true, return immediately without processing
1028
- private async deleteOldPasswords(user: User) {
1029
- const userPwdHistoryArray = await this.userPasswordHistoryRepository.findBy(
1030
- { user: { id: user.id } }
1031
- )
1032
- const pwdLimit = 2; //FIXME: Should this be moved into the env? IAM_PREVIOUS_PASSWORDS_LIMIT
1033
-
1034
- // TODO: Check what slice() or splice() does.
1035
- //FIXME - Delete passwords which are older than the latest n passwords. n is configurable
1036
- if (userPwdHistoryArray.length >= pwdLimit) {
1037
- const numToDelete = pwdLimit + 1 - userPwdHistoryArray.length;
1038
- for (let i = 0; i < numToDelete; i++) {
1039
- await this.userPasswordHistoryRepository.remove(userPwdHistoryArray[i]);
1040
- }
1041
- }
1042
- }
1043
-
1044
933
  async generateTokens(user: User) {
1045
934
 
1046
935
  const [accessToken, refreshToken] = await Promise.all([
@@ -1083,7 +972,7 @@ export class AuthenticationService {
1083
972
 
1084
973
  async refreshTokens(refreshTokenDto: RefreshTokenDto) {
1085
974
  try {
1086
- const { sub, refreshTokenId } = await this.jwtService.verifyAsync<Pick<ActiveUserData, 'sub'> & { refreshTokenId: string }>(refreshTokenDto.refreshToken, {
975
+ const { sub } = await this.jwtService.verifyAsync<Pick<ActiveUserData, 'sub'> & { refreshTokenId: string }>(refreshTokenDto.refreshToken, {
1087
976
  secret: this.jwtConfiguration.secret,
1088
977
  audience: this.jwtConfiguration.audience,
1089
978
  issuer: this.jwtConfiguration.issuer,
@@ -1185,7 +1074,7 @@ export class AuthenticationService {
1185
1074
  username: user.username,
1186
1075
  // forcePasswordChange: user.forcePasswordChange,
1187
1076
  id: user.id,
1188
- roles: user.roles.map((role, idx, roles) => role.name)
1077
+ roles: user.roles.map((role) => role.name)
1189
1078
  },
1190
1079
  ...tokens
1191
1080
  }
@@ -1255,7 +1144,7 @@ export class AuthenticationService {
1255
1144
  username: user.username,
1256
1145
  // forcePasswordChange: user.forcePasswordChange,
1257
1146
  id: user.id,
1258
- roles: user.roles.map((role, idx, roles) => role.name)
1147
+ roles: user.roles.map((role) => role.name)
1259
1148
  },
1260
1149
  ...tokens
1261
1150
  }