@solidstarters/solid-core 1.2.166 → 1.2.169

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 (80) hide show
  1. package/dist/config/iam.config.d.ts +2 -0
  2. package/dist/config/iam.config.d.ts.map +1 -1
  3. package/dist/config/iam.config.js +1 -0
  4. package/dist/config/iam.config.js.map +1 -1
  5. package/dist/dtos/create-ai-interaction.dto.d.ts +3 -0
  6. package/dist/dtos/create-ai-interaction.dto.d.ts.map +1 -1
  7. package/dist/dtos/create-ai-interaction.dto.js +19 -1
  8. package/dist/dtos/create-ai-interaction.dto.js.map +1 -1
  9. package/dist/dtos/post-chatter-message.dto.js.map +1 -1
  10. package/dist/dtos/update-ai-interaction.dto.d.ts +3 -0
  11. package/dist/dtos/update-ai-interaction.dto.d.ts.map +1 -1
  12. package/dist/dtos/update-ai-interaction.dto.js +19 -1
  13. package/dist/dtos/update-ai-interaction.dto.js.map +1 -1
  14. package/dist/entities/ai-interaction.entity.d.ts +3 -0
  15. package/dist/entities/ai-interaction.entity.d.ts.map +1 -1
  16. package/dist/entities/ai-interaction.entity.js +13 -1
  17. package/dist/entities/ai-interaction.entity.js.map +1 -1
  18. package/dist/entities/chatter-message.entity.js.map +1 -1
  19. package/dist/filters/http-exception.filter.d.ts.map +1 -1
  20. package/dist/filters/http-exception.filter.js +2 -1
  21. package/dist/filters/http-exception.filter.js.map +1 -1
  22. package/dist/helpers/security.helper.d.ts +4 -2
  23. package/dist/helpers/security.helper.d.ts.map +1 -1
  24. package/dist/helpers/security.helper.js +38 -23
  25. package/dist/helpers/security.helper.js.map +1 -1
  26. package/dist/helpers/solid-core-error-codes-provider.service.js +3 -3
  27. package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -1
  28. package/dist/helpers/solid-registry.d.ts +0 -1
  29. package/dist/helpers/solid-registry.d.ts.map +1 -1
  30. package/dist/helpers/solid-registry.js +0 -1
  31. package/dist/helpers/solid-registry.js.map +1 -1
  32. package/dist/index.d.ts +0 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +0 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +2 -2
  37. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  38. package/dist/seeders/seed-data/solid-core-metadata.json +33 -0
  39. package/dist/services/authentication.service.d.ts +1 -5
  40. package/dist/services/authentication.service.d.ts.map +1 -1
  41. package/dist/services/authentication.service.js +22 -63
  42. package/dist/services/authentication.service.js.map +1 -1
  43. package/dist/services/chatter-message.service.d.ts.map +1 -1
  44. package/dist/services/chatter-message.service.js.map +1 -1
  45. package/dist/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.js +1 -1
  46. package/dist/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.js.map +1 -1
  47. package/dist/services/model-metadata.service.js +1 -1
  48. package/dist/services/model-metadata.service.js.map +1 -1
  49. package/dist/services/setting.service.d.ts.map +1 -1
  50. package/dist/services/setting.service.js +2 -1
  51. package/dist/services/setting.service.js.map +1 -1
  52. package/dist/solid-core.module.d.ts.map +1 -1
  53. package/dist/solid-core.module.js +0 -2
  54. package/dist/solid-core.module.js.map +1 -1
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +1 -1
  57. package/src/config/iam.config.ts +1 -0
  58. package/src/dtos/create-ai-interaction.dto.ts +15 -0
  59. package/src/dtos/post-chatter-message.dto.ts +1 -1
  60. package/src/dtos/update-ai-interaction.dto.ts +15 -0
  61. package/src/entities/ai-interaction.entity.ts +9 -0
  62. package/src/entities/chatter-message.entity.ts +3 -3
  63. package/src/filters/http-exception.filter.ts +5 -2
  64. package/src/helpers/security.helper.ts +95 -30
  65. package/src/helpers/solid-core-error-codes-provider.service.ts +4 -4
  66. package/src/helpers/solid-registry.ts +0 -1
  67. package/src/index.ts +0 -1
  68. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +2 -2
  69. package/src/seeders/seed-data/solid-core-metadata.json +35 -2
  70. package/src/services/authentication.service.ts +31 -142
  71. package/src/services/chatter-message.service.ts +373 -374
  72. package/src/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.ts +1 -1
  73. package/src/services/model-metadata.service.ts +1 -1
  74. package/src/services/setting.service.ts +2 -1
  75. package/src/solid-core.module.ts +0 -8
  76. package/dist/entities/user-password-history.entity.d.ts +0 -7
  77. package/dist/entities/user-password-history.entity.d.ts.map +0 -1
  78. package/dist/entities/user-password-history.entity.js +0 -35
  79. package/dist/entities/user-password-history.entity.js.map +0 -1
  80. package/src/entities/user-password-history.entity.ts +0 -14
@@ -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)
@@ -196,7 +194,7 @@ export class AuthenticationService {
196
194
 
197
195
  private async populateForSignup<T extends User>(user: T, signUpDto: SignUpDto, isUserActive: boolean = true, onForcePasswordChange?: boolean) {
198
196
  // const user = new User();
199
-
197
+ let autoGeneratedPwdPermission = await this.settingService.getConfigValue('iamAutoGeneratedPassword');
200
198
  if (signUpDto.roles && signUpDto.roles.length > 0) {
201
199
  for (let i = 0; i < signUpDto.roles.length; i++) {
202
200
  const roleName = signUpDto.roles[i];
@@ -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
  }
221
+ // User has not specified password
220
222
  else {
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;
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
  }