@solidstarters/solid-core 1.2.157 → 1.2.158

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 (33) hide show
  1. package/dist/config/cache.options.js +2 -7
  2. package/dist/config/cache.options.js.map +1 -1
  3. package/dist/constants/error-messages.js +1 -1
  4. package/dist/constants/error-messages.js.map +1 -1
  5. package/dist/controllers/authentication.controller.d.ts +0 -2
  6. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  7. package/dist/controllers/authentication.controller.js +5 -5
  8. package/dist/controllers/authentication.controller.js.map +1 -1
  9. package/dist/helpers/environment.helper.d.ts +2 -0
  10. package/dist/helpers/environment.helper.d.ts.map +1 -1
  11. package/dist/helpers/environment.helper.js +7 -0
  12. package/dist/helpers/environment.helper.js.map +1 -1
  13. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  14. package/dist/seeders/module-metadata-seeder.service.js +2 -0
  15. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  16. package/dist/services/authentication.service.d.ts +0 -2
  17. package/dist/services/authentication.service.d.ts.map +1 -1
  18. package/dist/services/authentication.service.js +15 -14
  19. package/dist/services/authentication.service.js.map +1 -1
  20. package/dist/services/list-of-values.service.js.map +1 -1
  21. package/dist/solid-core.module.d.ts.map +1 -1
  22. package/dist/solid-core.module.js +14 -7
  23. package/dist/solid-core.module.js.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +2 -1
  26. package/src/config/cache.options.ts +1 -6
  27. package/src/constants/error-messages.ts +1 -1
  28. package/src/controllers/authentication.controller.ts +5 -5
  29. package/src/helpers/environment.helper.ts +9 -0
  30. package/src/seeders/module-metadata-seeder.service.ts +2 -0
  31. package/src/services/authentication.service.ts +20 -14
  32. package/src/services/list-of-values.service.ts +1 -1
  33. package/src/solid-core.module.ts +10 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.157",
3
+ "version": "1.2.158",
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",
@@ -38,6 +38,7 @@
38
38
  "@aws-sdk/s3-request-presigner": "^3.828.0",
39
39
  "@elasticemail/elasticemail-client": "^4.0.23",
40
40
  "@hapi/joi": "^17.1.1",
41
+ "@nest-lab/throttler-storage-redis": "^1.1.0",
41
42
  "@nestjs/schedule": "^6.0.0",
42
43
  "@nestjs/throttler": "^6.4.0",
43
44
  "amqplib": "^0.10.4",
@@ -1,7 +1,7 @@
1
1
  import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
2
2
  import { ConfigModule, ConfigService } from '@nestjs/config';
3
3
  import { redisStore } from 'cache-manager-redis-store';
4
- import { isNumber } from 'class-validator';
4
+ import { isRedisConfigured } from 'src/helpers/environment.helper';
5
5
 
6
6
  export const RedisOptions: CacheModuleAsyncOptions = {
7
7
  isGlobal: true,
@@ -29,8 +29,3 @@ async function createRedisStore(configService: ConfigService<Record<string, unkn
29
29
  });
30
30
  }
31
31
 
32
- function isRedisConfigured(configService: ConfigService): boolean {
33
- const host = configService.get<string>('REDIS_HOST');
34
- const port = configService.get<string>('REDIS_PORT');
35
- return host && port && isNumber(parseInt(port));
36
- }
@@ -28,7 +28,7 @@ export const ERROR_MESSAGES = {
28
28
  GOOGLE_OAUTH_PROFILE_FETCH_FAILED: 'Failed to fetch user profile from Google OAuth service',
29
29
  LOGOUT_FAILED: 'Logout failed due to an unexpected error.',
30
30
 
31
- INVALID_CREDENTIALS: 'Invalid username or password specified.',
31
+ INVALID_CREDENTIALS: 'Invalid credentials',
32
32
  LOGIN_FAILED: 'Login Failed',
33
33
  OLD_PASSWORD_INCORRECT: 'You have specified an incorrect old password.',
34
34
  INVALID_NEW_PASSWORD: 'Invalid new password.',
@@ -25,7 +25,7 @@ export class AuthenticationController {
25
25
  constructor(private readonly authService: AuthenticationService) { }
26
26
 
27
27
  @Public()
28
- @SkipThrottle({ login: false }) //Enable the login throttle only
28
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
29
29
  @Post('register')
30
30
  signUp(@Body() signUpDto: SignUpDto) {
31
31
  return this.authService.signUp(signUpDto);
@@ -39,7 +39,7 @@ export class AuthenticationController {
39
39
 
40
40
  @Public()
41
41
  // @UseGuards(LocalAuthGuard)
42
- @SkipThrottle({ login: false }) //Enable the login throttle only
42
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
43
43
  @HttpCode(HttpStatus.OK) // by default @Post does 201, we wanted 200 - hence using @HttpCode(HttpStatus.OK)
44
44
  @Post('authenticate')
45
45
  async signIn(
@@ -62,7 +62,7 @@ export class AuthenticationController {
62
62
  }
63
63
 
64
64
  @Public()
65
- @SkipThrottle({ login: false }) //Enable the login throttle only
65
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
66
66
  @HttpCode(HttpStatus.OK) // changed since the default is 201
67
67
  @Post('refresh-tokens')
68
68
  refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {
@@ -70,14 +70,14 @@ export class AuthenticationController {
70
70
  }
71
71
 
72
72
  @Public()
73
- @SkipThrottle({ login: false }) //Enable the login throttle only
73
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
74
74
  @Post('initiate/forgot-password')
75
75
  initiateForgotPassword(@Body() initiateForgotPasswordDto: InitiateForgotPasswordDto) {
76
76
  return this.authService.initiateForgotPassword(initiateForgotPasswordDto);
77
77
  }
78
78
 
79
79
  @Public()
80
- @SkipThrottle({ login: false }) //Enable the login throttle only
80
+ @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
81
81
  @Post('confirm/forgot-password')
82
82
  confirmForgotPassword(@Body() confirmForgotPasswordDto: ConfirmForgotPasswordDto) {
83
83
  return this.authService.confirmForgotPassword(confirmForgotPasswordDto);
@@ -1,7 +1,16 @@
1
+ import { ConfigService } from "@nestjs/config";
2
+ import { isNumber } from 'class-validator';
3
+
1
4
  export function parseBooleanEnv(key: string, defaultValue: boolean = false): boolean {
2
5
  const value = process.env[key];
3
6
  if (value === undefined) {
4
7
  return defaultValue;
5
8
  }
6
9
  return value.toLowerCase() === 'true';
10
+ }
11
+
12
+ export function isRedisConfigured(configService: ConfigService): boolean {
13
+ const host = configService.get<string>('REDIS_HOST');
14
+ const port = configService.get<string>('REDIS_PORT');
15
+ return host && port && isNumber(parseInt(port));
7
16
  }
@@ -584,6 +584,8 @@ export class ModuleMetadataSeederService {
584
584
  return;
585
585
  }
586
586
  for (let j = 0; j < listOfValuesDto.length; j++) {
587
+ const listOfValueDto = listOfValuesDto[j];
588
+ listOfValueDto['module'] = await this.moduleMetadataService.findOneByUserKey(listOfValueDto.moduleUserKey);
587
589
  await this.listOfValuesService.upsert(listOfValuesDto[j]);
588
590
  }
589
591
  }
@@ -126,7 +126,7 @@ export class AuthenticationService {
126
126
  const user = await this.resolveUser(signInDto.username, signInDto.email);
127
127
 
128
128
  if (!user) {
129
- throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
129
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
130
130
  }
131
131
  if (!user.active) {
132
132
  throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_ACTIVE);
@@ -136,7 +136,7 @@ export class AuthenticationService {
136
136
  user.password,
137
137
  );
138
138
  if (!isEqual) {
139
- throw new UnauthorizedException(ERROR_MESSAGES.PASSWORD_INCORRECT);
139
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
140
140
  }
141
141
 
142
142
  return user;
@@ -759,25 +759,31 @@ export class AuthenticationService {
759
759
  // });
760
760
  const user = await this.resolveUser(initiateForgotPasswordDto.username, initiateForgotPasswordDto.email);
761
761
 
762
+ let isValidUser = true // Instead of throwing exceptions we will simply return success message, this is to avoid user enumeration attacks.
762
763
  if (!user) {
763
- throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
764
+ isValidUser = false
765
+ // throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
764
766
  }
765
767
  if (!user.active) {
766
- throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
768
+ isValidUser = false
769
+ // throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
767
770
  }
768
771
 
769
772
  // 2. Validate if user has used a provider which is "local", only then it makes sense for us to initiate the forgot password routine.
770
773
  if (user.lastLoginProvider !== 'local') {
771
- throw new BadRequestException(ERROR_MESSAGES.INVALID_CREDENTIALS);
774
+ isValidUser = false
775
+ // throw new BadRequestException(ERROR_MESSAGES.INVALID_CREDENTIALS);
772
776
  }
773
777
 
774
778
  // 3. Generate a 6 digit validation token, we send this token to the user over their email & mobile number (controlled using configuration).
775
779
  // 4. Save this validation token in new fields on the user record.
776
- const { token, expiresAt } = this.generateForgotPasswordToken();
777
- user.verificationTokenOnForgotPassword = token;
778
- user.verificationTokenOnForgotPasswordExpiresAt = expiresAt;
779
- await this.userRepository.save(user);
780
- this.notifyUserOnForgotPassword(user);
780
+ if (isValidUser) {
781
+ const { token, expiresAt } = this.generateForgotPasswordToken();
782
+ user.verificationTokenOnForgotPassword = token;
783
+ user.verificationTokenOnForgotPasswordExpiresAt = expiresAt;
784
+ await this.userRepository.save(user);
785
+ this.notifyUserOnForgotPassword(user);
786
+ }
781
787
 
782
788
  // 5. Return.
783
789
  return {
@@ -788,8 +794,8 @@ export class AuthenticationService {
788
794
  data: {
789
795
  user: {
790
796
  email: user.email,
791
- mobile: user.mobile,
792
- username: user.username,
797
+ // mobile: user.mobile,
798
+ // username: user.username,
793
799
  },
794
800
  }
795
801
  }
@@ -841,8 +847,8 @@ export class AuthenticationService {
841
847
  return this.dataSource.transaction(async (m) => {
842
848
  // Resolve the user id first (by username/email), but DON'T check the token in JS.
843
849
  const user = await this.resolveUserByVerificationToken(confirmForgotPasswordDto.verificationToken);
844
- if (!user) throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
845
- if (user.lastLoginProvider !== 'local') throw new BadRequestException(ERROR_MESSAGES.INVALID_CREDENTIALS);
850
+ if (!user) throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
851
+ if (user.lastLoginProvider !== 'local') throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
846
852
  if (!user.active) throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
847
853
 
848
854
  // 1) Atomically consume the token (only one request can succeed)
@@ -43,7 +43,7 @@ export class ListOfValuesService extends CRUDService<ListOfValues> {
43
43
  async findAll(): Promise<ListOfValues[]> {
44
44
  return await this.repo.find();
45
45
  }
46
-
46
+
47
47
  async upsert(updateListOfValuesDto: any) {
48
48
  // First check if module already exists using name
49
49
  const existingListOfValue = await this.repo.findOne({
@@ -281,6 +281,8 @@ import { Three60WhatsappQueueSubscriber } from './jobs/three60-whatsapp-subscrib
281
281
  import { Three60WhatsappQueuePublisherDatabase } from './jobs/database/three60-whatsapp-publisher-database.service';
282
282
  import { Three60WhatsappQueueSubscriberDatabase } from './jobs/database/three60-whatsapp-subscriber-database.service';
283
283
  import { Three60WhatsappService } from './services/whatsapp/Three60WhatsappService';
284
+ import { ThrottlerStorageRedisService } from '@nest-lab/throttler-storage-redis/src/throttler-storage-redis.service';
285
+ import { isRedisConfigured } from './helpers/environment.helper';
284
286
 
285
287
 
286
288
  @Global()
@@ -356,13 +358,18 @@ import { Three60WhatsappService } from './services/whatsapp/Three60WhatsappServi
356
358
  HttpModule,
357
359
  ConfigModule,
358
360
  ClsModule,
359
- ThrottlerModule.forRoot({
360
- throttlers: [
361
+ ThrottlerModule.forRootAsync({
362
+ imports: [ConfigModule],
363
+ inject: [ConfigService],
364
+ useFactory: (configService: ConfigService) => ({
365
+ throttlers: [
361
366
  { name: 'short', ttl: seconds(10), limit: 10 },
362
367
  { name: 'login', ttl: seconds(10), limit: 5 },
363
368
  { name: 'burst', ttl: seconds(1), limit: 100 },
364
369
  { name: 'sustained', ttl: seconds(300), limit: 500 },
365
- ],
370
+ ],
371
+ storage: isRedisConfigured(configService) ? new ThrottlerStorageRedisService(`redis://${configService.get<string>('REDIS_HOST')}:${configService.get<string>('REDIS_PORT')}`) : undefined,
372
+ }),
366
373
  }),
367
374
  ],
368
375
  controllers: [