@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.
- package/dist/config/iam.config.d.ts +2 -0
- package/dist/config/iam.config.d.ts.map +1 -1
- package/dist/config/iam.config.js +1 -0
- package/dist/config/iam.config.js.map +1 -1
- package/dist/dtos/create-ai-interaction.dto.d.ts +3 -0
- package/dist/dtos/create-ai-interaction.dto.d.ts.map +1 -1
- package/dist/dtos/create-ai-interaction.dto.js +19 -1
- package/dist/dtos/create-ai-interaction.dto.js.map +1 -1
- package/dist/dtos/post-chatter-message.dto.js.map +1 -1
- package/dist/dtos/update-ai-interaction.dto.d.ts +3 -0
- package/dist/dtos/update-ai-interaction.dto.d.ts.map +1 -1
- package/dist/dtos/update-ai-interaction.dto.js +19 -1
- package/dist/dtos/update-ai-interaction.dto.js.map +1 -1
- package/dist/entities/ai-interaction.entity.d.ts +3 -0
- package/dist/entities/ai-interaction.entity.d.ts.map +1 -1
- package/dist/entities/ai-interaction.entity.js +13 -1
- package/dist/entities/ai-interaction.entity.js.map +1 -1
- package/dist/entities/chatter-message.entity.js.map +1 -1
- package/dist/filters/http-exception.filter.d.ts.map +1 -1
- package/dist/filters/http-exception.filter.js +2 -1
- package/dist/filters/http-exception.filter.js.map +1 -1
- package/dist/helpers/security.helper.d.ts +4 -2
- package/dist/helpers/security.helper.d.ts.map +1 -1
- package/dist/helpers/security.helper.js +38 -23
- package/dist/helpers/security.helper.js.map +1 -1
- package/dist/helpers/solid-core-error-codes-provider.service.js +3 -3
- package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -1
- package/dist/helpers/solid-registry.d.ts +0 -1
- package/dist/helpers/solid-registry.d.ts.map +1 -1
- package/dist/helpers/solid-registry.js +0 -1
- package/dist/helpers/solid-registry.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +2 -2
- package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +33 -0
- package/dist/services/authentication.service.d.ts +1 -5
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +22 -63
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.js +1 -1
- package/dist/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.js.map +1 -1
- package/dist/services/model-metadata.service.js +1 -1
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +2 -1
- package/dist/services/setting.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +0 -2
- package/dist/solid-core.module.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config/iam.config.ts +1 -0
- package/src/dtos/create-ai-interaction.dto.ts +15 -0
- package/src/dtos/post-chatter-message.dto.ts +1 -1
- package/src/dtos/update-ai-interaction.dto.ts +15 -0
- package/src/entities/ai-interaction.entity.ts +9 -0
- package/src/entities/chatter-message.entity.ts +3 -3
- package/src/filters/http-exception.filter.ts +5 -2
- package/src/helpers/security.helper.ts +95 -30
- package/src/helpers/solid-core-error-codes-provider.service.ts +4 -4
- package/src/helpers/solid-registry.ts +0 -1
- package/src/index.ts +0 -1
- package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +2 -2
- package/src/seeders/seed-data/solid-core-metadata.json +35 -2
- package/src/services/authentication.service.ts +31 -142
- package/src/services/chatter-message.service.ts +373 -374
- package/src/services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service.ts +1 -1
- package/src/services/model-metadata.service.ts +1 -1
- package/src/services/setting.service.ts +2 -1
- package/src/solid-core.module.ts +0 -8
- package/dist/entities/user-password-history.entity.d.ts +0 -7
- package/dist/entities/user-password-history.entity.d.ts.map +0 -1
- package/dist/entities/user-password-history.entity.js +0 -35
- package/dist/entities/user-password-history.entity.js.map +0 -1
- 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
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1147
|
+
roles: user.roles.map((role) => role.name)
|
|
1259
1148
|
},
|
|
1260
1149
|
...tokens
|
|
1261
1150
|
}
|