@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.
- package/dist/config/cache.options.js +2 -7
- package/dist/config/cache.options.js.map +1 -1
- package/dist/constants/error-messages.js +1 -1
- package/dist/constants/error-messages.js.map +1 -1
- package/dist/controllers/authentication.controller.d.ts +0 -2
- package/dist/controllers/authentication.controller.d.ts.map +1 -1
- package/dist/controllers/authentication.controller.js +5 -5
- package/dist/controllers/authentication.controller.js.map +1 -1
- package/dist/helpers/environment.helper.d.ts +2 -0
- package/dist/helpers/environment.helper.d.ts.map +1 -1
- package/dist/helpers/environment.helper.js +7 -0
- package/dist/helpers/environment.helper.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +2 -0
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/services/authentication.service.d.ts +0 -2
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +15 -14
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/list-of-values.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +14 -7
- package/dist/solid-core.module.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/config/cache.options.ts +1 -6
- package/src/constants/error-messages.ts +1 -1
- package/src/controllers/authentication.controller.ts +5 -5
- package/src/helpers/environment.helper.ts +9 -0
- package/src/seeders/module-metadata-seeder.service.ts +2 -0
- package/src/services/authentication.service.ts +20 -14
- package/src/services/list-of-values.service.ts +1 -1
- 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.
|
|
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 {
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
764
|
+
isValidUser = false
|
|
765
|
+
// throw new NotFoundException(ERROR_MESSAGES.INVALID_CREDENTIALS);
|
|
764
766
|
}
|
|
765
767
|
if (!user.active) {
|
|
766
|
-
|
|
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
|
-
|
|
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
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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
|
|
845
|
-
if (user.lastLoginProvider !== 'local') throw new
|
|
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({
|
package/src/solid-core.module.ts
CHANGED
|
@@ -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.
|
|
360
|
-
|
|
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: [
|