@solidstarters/solid-core 1.2.169 → 1.2.171
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 +2 -1
- package/dist/config/iam.config.js.map +1 -1
- package/dist/controllers/authentication.controller.d.ts.map +1 -1
- package/dist/controllers/authentication.controller.js +0 -8
- package/dist/controllers/authentication.controller.js.map +1 -1
- package/dist/controllers/email-template.controller.d.ts +1 -1
- package/dist/controllers/email-template.controller.d.ts.map +1 -1
- package/dist/controllers/email-template.controller.js +3 -6
- package/dist/controllers/email-template.controller.js.map +1 -1
- package/dist/controllers/google-authentication.controller.d.ts +3 -3
- package/dist/controllers/google-authentication.controller.d.ts.map +1 -1
- package/dist/controllers/google-authentication.controller.js +5 -8
- package/dist/controllers/google-authentication.controller.js.map +1 -1
- package/dist/controllers/media.controller.d.ts +1 -1
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +1 -5
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/controllers/model-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/model-metadata.controller.js +0 -5
- package/dist/controllers/model-metadata.controller.js.map +1 -1
- package/dist/controllers/otp-authentication.controller.js +0 -3
- package/dist/controllers/otp-authentication.controller.js.map +1 -1
- package/dist/controllers/service.controller.d.ts +2 -2
- package/dist/controllers/service.controller.d.ts.map +1 -1
- package/dist/controllers/service.controller.js +3 -7
- package/dist/controllers/service.controller.js.map +1 -1
- package/dist/controllers/sms-template.controller.d.ts.map +1 -1
- package/dist/controllers/sms-template.controller.js +0 -3
- package/dist/controllers/sms-template.controller.js.map +1 -1
- package/dist/entities/user.entity.d.ts +3 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +13 -1
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/filters/http-exception.filter.js +1 -1
- package/dist/filters/http-exception.filter.js.map +1 -1
- package/dist/helpers/error-mapper.service.d.ts.map +1 -1
- package/dist/helpers/error-mapper.service.js +1 -1
- package/dist/helpers/error-mapper.service.js.map +1 -1
- package/dist/helpers/field-crud-managers/PasswordFieldCrudManager.d.ts +2 -1
- package/dist/helpers/field-crud-managers/PasswordFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/PasswordFieldCrudManager.js +3 -3
- package/dist/helpers/field-crud-managers/PasswordFieldCrudManager.js.map +1 -1
- package/dist/helpers/model-metadata-helper.service.js.map +1 -1
- package/dist/passport-strategies/local.strategy.js +1 -1
- package/dist/passport-strategies/local.strategy.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +43 -0
- package/dist/services/authentication.service.d.ts +2 -1
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +28 -5
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/bcrypt.service.d.ts +11 -1
- package/dist/services/bcrypt.service.d.ts.map +1 -1
- package/dist/services/bcrypt.service.js +35 -5
- package/dist/services/bcrypt.service.js.map +1 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +2 -1
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/export-transaction.service.d.ts +3 -1
- package/dist/services/export-transaction.service.d.ts.map +1 -1
- package/dist/services/export-transaction.service.js +70 -16
- package/dist/services/export-transaction.service.js.map +1 -1
- package/dist/services/hashing.service.d.ts +4 -1
- package/dist/services/hashing.service.d.ts.map +1 -1
- package/dist/services/hashing.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +46 -61
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
- package/dist/subscribers/audit.subscriber.js +1 -1
- package/dist/subscribers/audit.subscriber.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config/iam.config.ts +2 -1
- package/src/controllers/authentication.controller.ts +8 -10
- package/src/controllers/email-template.controller.ts +7 -10
- package/src/controllers/google-authentication.controller.ts +9 -10
- package/src/controllers/media.controller.ts +5 -6
- package/src/controllers/model-metadata.controller.ts +5 -6
- package/src/controllers/otp-authentication.controller.ts +2 -2
- package/src/controllers/service.controller.ts +8 -9
- package/src/controllers/sms-template.controller.ts +3 -4
- package/src/entities/user.entity.ts +9 -0
- package/src/filters/http-exception.filter.ts +1 -1
- package/src/helpers/error-mapper.service.ts +1 -35
- package/src/helpers/field-crud-managers/PasswordFieldCrudManager.ts +4 -3
- package/src/helpers/model-metadata-helper.service.ts +1 -1
- package/src/passport-strategies/local.strategy.ts +1 -1
- package/src/seeders/seed-data/solid-core-metadata.json +43 -0
- package/src/services/authentication.service.ts +32 -3
- package/src/services/bcrypt.service.ts +45 -7
- package/src/services/crud.service.ts +2 -1
- package/src/services/export-transaction.service.ts +118 -55
- package/src/services/hashing.service.ts +5 -2
- package/src/solid-core.module.ts +59 -61
- package/src/subscribers/audit.subscriber.ts +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.171",
|
|
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",
|
package/src/config/iam.config.ts
CHANGED
|
@@ -22,7 +22,8 @@ export const iamConfig = registerAs('iam', () => {
|
|
|
22
22
|
callbackURL: process.env.IAM_GOOGLE_OAUTH_CALLBACK_URL,
|
|
23
23
|
redirectURL: process.env.IAM_GOOGLE_OAUTH_REDIRECT_URL,
|
|
24
24
|
},
|
|
25
|
-
iamAutoGeneratedPassword:process.env.IAM_AUTOGENERATED_PASSWORD || true
|
|
25
|
+
iamAutoGeneratedPassword:process.env.IAM_AUTOGENERATED_PASSWORD || true,
|
|
26
|
+
passwordPepper: process.env.IAM_PASSWORD_PEPPER || '', // Adding a pepper to the password hashing process for extra security
|
|
26
27
|
};
|
|
27
28
|
})
|
|
28
29
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Body, Controller, Get, HttpCode, HttpStatus, Logger, Post, Res
|
|
1
|
+
import { Body, Controller, Get, HttpCode, HttpStatus, Logger, Post, Res } from '@nestjs/common';
|
|
2
2
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|
3
|
-
import { SkipThrottle, ThrottlerGuard } from '@nestjs/throttler';
|
|
4
3
|
import { Response } from 'express';
|
|
5
4
|
import { ActiveUser } from "../decorators/active-user.decorator";
|
|
6
5
|
import { Public } from '../decorators/public.decorator';
|
|
@@ -17,15 +16,15 @@ import { AuthenticationService } from '../services/authentication.service';
|
|
|
17
16
|
// @Auth(AuthType.None)
|
|
18
17
|
@Controller('iam')
|
|
19
18
|
@ApiTags("Iam")
|
|
20
|
-
@UseGuards(ThrottlerGuard)
|
|
21
|
-
@SkipThrottle({login: true, short: true, burst: true, sustained: true}) // disable all sets by default for this controller
|
|
19
|
+
// @UseGuards(ThrottlerGuard)
|
|
20
|
+
// @SkipThrottle({login: true, short: true, burst: true, sustained: true}) // disable all sets by default for this controller
|
|
22
21
|
export class AuthenticationController {
|
|
23
22
|
private readonly logger = new Logger(AuthenticationController.name);
|
|
24
23
|
|
|
25
24
|
constructor(private readonly authService: AuthenticationService) { }
|
|
26
25
|
|
|
27
26
|
@Public()
|
|
28
|
-
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
27
|
+
// @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
29
28
|
@Post('register')
|
|
30
29
|
signUp(@Body() signUpDto: SignUpDto) {
|
|
31
30
|
return this.authService.signUp(signUpDto);
|
|
@@ -38,8 +37,7 @@ export class AuthenticationController {
|
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
@Public()
|
|
41
|
-
// @
|
|
42
|
-
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
40
|
+
// @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
43
41
|
@HttpCode(HttpStatus.OK) // by default @Post does 201, we wanted 200 - hence using @HttpCode(HttpStatus.OK)
|
|
44
42
|
@Post('authenticate')
|
|
45
43
|
async signIn(
|
|
@@ -62,7 +60,7 @@ export class AuthenticationController {
|
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
@Public()
|
|
65
|
-
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
63
|
+
// @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
66
64
|
@HttpCode(HttpStatus.OK) // changed since the default is 201
|
|
67
65
|
@Post('refresh-tokens')
|
|
68
66
|
refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {
|
|
@@ -70,14 +68,14 @@ export class AuthenticationController {
|
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
@Public()
|
|
73
|
-
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
71
|
+
// @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
74
72
|
@Post('initiate/forgot-password')
|
|
75
73
|
initiateForgotPassword(@Body() initiateForgotPasswordDto: InitiateForgotPasswordDto) {
|
|
76
74
|
return this.authService.initiateForgotPassword(initiateForgotPasswordDto);
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
@Public()
|
|
80
|
-
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
78
|
+
// @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
81
79
|
@Post('confirm/forgot-password')
|
|
82
80
|
confirmForgotPassword(@Body() confirmForgotPasswordDto: ConfirmForgotPasswordDto) {
|
|
83
81
|
return this.authService.confirmForgotPassword(confirmForgotPasswordDto);
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Header, Param,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { EmailTemplateService } from '../services/email-template.service';
|
|
1
|
+
import { Body, Controller, Delete, Get, Header, Param, Post, Put, Query, UploadedFiles, UseInterceptors } from '@nestjs/common';
|
|
2
|
+
import { AnyFilesInterceptor } from '@nestjs/platform-express';
|
|
3
|
+
import { ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
|
+
import { Public } from 'src/decorators/public.decorator';
|
|
6
5
|
import { CreateEmailTemplateDto } from '../dtos/create-email-template.dto';
|
|
7
6
|
import { UpdateEmailTemplateDto } from '../dtos/update-email-template.dto';
|
|
8
|
-
import {
|
|
7
|
+
import { EmailTemplateService } from '../services/email-template.service';
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
// TODO: esInterop not working somehow, defaulted to using the require syntax to import Mailgen. Figure a better way to do this.
|
|
13
12
|
// import { Mailgen } from 'mailgen';
|
|
14
13
|
import Mailgen = require('mailgen');
|
|
15
|
-
import { AnyFilesInterceptor } from '@nestjs/platform-express';
|
|
16
|
-
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
17
14
|
|
|
18
15
|
|
|
19
16
|
@Controller('email-template')
|
|
20
17
|
@ApiTags("Common")
|
|
21
|
-
@UseGuards(ThrottlerGuard)
|
|
22
|
-
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
18
|
+
// @UseGuards(ThrottlerGuard)
|
|
19
|
+
// @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
23
20
|
export class EmailTemplateController {
|
|
24
21
|
constructor(private readonly service: EmailTemplateService) { }
|
|
25
22
|
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { Controller, Get, Inject, InternalServerErrorException, Query, Req, Res, UseGuards } from '@nestjs/common';
|
|
2
|
-
import {
|
|
2
|
+
import { ConfigType } from '@nestjs/config';
|
|
3
|
+
import { ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
|
+
import { Request, Response } from 'express';
|
|
5
|
+
import { isGoogleOAuthConfigured } from 'src/helpers/google-oauth.helper';
|
|
6
|
+
import { iamConfig } from '../config/iam.config';
|
|
3
7
|
import { Auth } from '../decorators/auth.decorator';
|
|
8
|
+
import { Public } from '../decorators/public.decorator';
|
|
4
9
|
import { AuthType } from '../enums/auth-type.enum';
|
|
5
|
-
import { ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
6
10
|
import { GoogleOauthGuard } from '../passport-strategies/google-oauth.strategy';
|
|
7
|
-
import {
|
|
8
|
-
import { ConfigType } from '@nestjs/config';
|
|
11
|
+
import { AuthenticationService } from '../services/authentication.service';
|
|
9
12
|
import { UserService } from '../services/user.service';
|
|
10
|
-
import { Public } from '../decorators/public.decorator';
|
|
11
|
-
import { iamConfig } from '../config/iam.config';
|
|
12
|
-
import { isGoogleOAuthConfigured } from 'src/helpers/google-oauth.helper';
|
|
13
|
-
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
@Auth(AuthType.None)
|
|
18
17
|
@Controller('iam/google')
|
|
19
18
|
@ApiTags("Iam")
|
|
20
|
-
@UseGuards(ThrottlerGuard)
|
|
21
|
-
@SkipThrottle({ login: false, short: false, burst: true, sustained: true }) //Enable the login throttle only
|
|
19
|
+
// @UseGuards(ThrottlerGuard)
|
|
20
|
+
// @SkipThrottle({ login: false, short: false, burst: true, sustained: true }) //Enable the login throttle only
|
|
22
21
|
export class GoogleAuthenticationController {
|
|
23
22
|
constructor(
|
|
24
23
|
@Inject(iamConfig.KEY) private iamConfiguration: ConfigType<typeof iamConfig>,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { Controller,
|
|
1
|
+
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, UploadedFiles, UseInterceptors } from '@nestjs/common';
|
|
2
2
|
import { AnyFilesInterceptor } from "@nestjs/platform-express";
|
|
3
3
|
import { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
4
|
import { Public } from 'src/decorators/public.decorator';
|
|
5
|
-
import { MediaService } from 'src/services/media.service';
|
|
6
5
|
import { CreateMediaDto } from 'src/dtos/create-media.dto';
|
|
7
6
|
import { UpdateMediaDto } from 'src/dtos/update-media.dto';
|
|
8
|
-
import {
|
|
7
|
+
import { MediaService } from 'src/services/media.service';
|
|
9
8
|
|
|
10
9
|
enum ShowSoftDeleted {
|
|
11
10
|
INCLUSIVE = "inclusive",
|
|
@@ -14,8 +13,8 @@ enum ShowSoftDeleted {
|
|
|
14
13
|
|
|
15
14
|
@ApiTags('Solid Core')
|
|
16
15
|
@Controller('media')
|
|
17
|
-
@UseGuards(ThrottlerGuard)
|
|
18
|
-
@SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
16
|
+
// @UseGuards(ThrottlerGuard)
|
|
17
|
+
// @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
19
18
|
export class MediaController {
|
|
20
19
|
constructor(private readonly service: MediaService) {}
|
|
21
20
|
|
|
@@ -49,7 +48,7 @@ export class MediaController {
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
@Public()
|
|
52
|
-
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
51
|
+
// @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
53
52
|
@ApiBearerAuth("jwt")
|
|
54
53
|
@Post('/upload')
|
|
55
54
|
@UseInterceptors(AnyFilesInterceptor())
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Logger, Param, ParseIntPipe, Post, Put, Query
|
|
1
|
+
import { Body, Controller, Delete, Get, Logger, Param, ParseIntPipe, Post, Put, Query } from '@nestjs/common';
|
|
2
2
|
import { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
3
3
|
import { Public } from 'src/decorators/public.decorator';
|
|
4
4
|
import { BasicFilterDto } from '../dtos/basic-filters.dto';
|
|
5
5
|
import { CreateModelMetadataDto } from '../dtos/create-model-metadata.dto';
|
|
6
6
|
import { UpdateModelMetaDataDto } from '../dtos/update-model-metadata.dto';
|
|
7
7
|
import { ModelMetadataService } from '../services/model-metadata.service';
|
|
8
|
-
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
9
8
|
|
|
10
9
|
@Controller('model-metadata')
|
|
11
10
|
@ApiTags("App Builder")
|
|
12
|
-
@UseGuards(ThrottlerGuard)
|
|
13
|
-
@SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
11
|
+
// @UseGuards(ThrottlerGuard)
|
|
12
|
+
// @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
14
13
|
export class ModelMetadataController {
|
|
15
14
|
private logger = new Logger('ModelMetadataController');
|
|
16
15
|
|
|
@@ -35,7 +34,7 @@ export class ModelMetadataController {
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
@Public()
|
|
38
|
-
@SkipThrottle({ burst: false, short: true, login: true, sustained: true }) //Enable burst only
|
|
37
|
+
// @SkipThrottle({ burst: false, short: true, login: true, sustained: true }) //Enable burst only
|
|
39
38
|
@Get('public')
|
|
40
39
|
async findManyPublic() {
|
|
41
40
|
const basicFilterDto: BasicFilterDto = {
|
|
@@ -65,7 +64,7 @@ export class ModelMetadataController {
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
@Public()
|
|
68
|
-
@SkipThrottle({ short: false, burst: true, login: true, sustained: true }) //Enable short only
|
|
67
|
+
// @SkipThrottle({ short: false, burst: true, login: true, sustained: true }) //Enable short only
|
|
69
68
|
@Post('/update-user-key')
|
|
70
69
|
updateUserKey(@Body() data: any) {
|
|
71
70
|
return this.modelMetadataService.updateUserKey(data);
|
|
@@ -14,8 +14,8 @@ import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
|
14
14
|
@Auth(AuthType.None)
|
|
15
15
|
@Controller('iam/otp')
|
|
16
16
|
@ApiTags("Iam")
|
|
17
|
-
@UseGuards(ThrottlerGuard)
|
|
18
|
-
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
17
|
+
// @UseGuards(ThrottlerGuard)
|
|
18
|
+
// @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
19
19
|
export class OTPAuthenticationController {
|
|
20
20
|
constructor(private readonly authService: AuthenticationService) { }
|
|
21
21
|
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import { Body, Controller, Get, Logger, Post
|
|
2
|
-
import { Public } from 'src/decorators/public.decorator';
|
|
3
|
-
import { SolidRegistry } from '../helpers/solid-registry';
|
|
1
|
+
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
|
4
2
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|
5
|
-
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
6
|
-
import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
|
|
7
3
|
import { ActiveUser } from 'src/decorators/active-user.decorator';
|
|
4
|
+
import { Public } from 'src/decorators/public.decorator';
|
|
5
|
+
import { ErrorMapperService } from 'src/helpers/error-mapper.service';
|
|
6
|
+
import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
|
|
8
7
|
import { AiInteractionService } from 'src/services/ai-interaction.service';
|
|
9
8
|
import { MqMessageService } from 'src/services/mq-message.service';
|
|
10
|
-
import {
|
|
9
|
+
import { SolidRegistry } from '../helpers/solid-registry';
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
@Controller('')
|
|
14
13
|
@ApiTags("Common")
|
|
15
|
-
@UseGuards(ThrottlerGuard)
|
|
16
|
-
@SkipThrottle({ short: true, login: true, burst: true, sustained: true }) // Skip all
|
|
14
|
+
// @UseGuards(ThrottlerGuard)
|
|
15
|
+
// @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) // Skip all
|
|
17
16
|
export class ServiceController {
|
|
18
17
|
private readonly logger = new Logger(ServiceController.name);
|
|
19
18
|
|
|
@@ -87,7 +86,7 @@ export class ServiceController {
|
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
@Public()
|
|
90
|
-
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
89
|
+
// @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
91
90
|
@Post('seed')
|
|
92
91
|
async seedData(@Body() seedData: any) {
|
|
93
92
|
const seeder = this.solidRegistry
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Param, Post, Put, Query, UploadedFiles,
|
|
1
|
+
import { Body, Controller, Delete, Get, Param, Post, Put, Query, UploadedFiles, UseInterceptors } from '@nestjs/common';
|
|
2
2
|
import { AnyFilesInterceptor } from '@nestjs/platform-express';
|
|
3
3
|
import { ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
|
-
import { SkipThrottle, ThrottlerGuard } from '@nestjs/throttler';
|
|
5
4
|
import { Public } from 'src/decorators/public.decorator';
|
|
6
5
|
import { CreateSmsTemplateDto } from '../dtos/create-sms-template.dto';
|
|
7
6
|
import { UpdateSmsTemplateDto } from '../dtos/update-sms-template.dto';
|
|
@@ -10,8 +9,8 @@ import { SmsTemplateService } from '../services/sms-template.service';
|
|
|
10
9
|
|
|
11
10
|
@Controller('sms-template')
|
|
12
11
|
@ApiTags("Common")
|
|
13
|
-
@UseGuards(ThrottlerGuard)
|
|
14
|
-
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
12
|
+
// @UseGuards(ThrottlerGuard)
|
|
13
|
+
// @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
15
14
|
export class SmsTemplateController {
|
|
16
15
|
constructor(private readonly service: SmsTemplateService) { }
|
|
17
16
|
|
|
@@ -102,4 +102,13 @@ export class User extends CommonEntity {
|
|
|
102
102
|
@OneToMany(() => UserViewMetadata, userViewMetadata => userViewMetadata.user, { cascade: true })
|
|
103
103
|
// don't send to client
|
|
104
104
|
userViewMetadata: UserViewMetadata[];
|
|
105
|
+
// dont send to client
|
|
106
|
+
@Column({ type: "varchar", default: "bcrypt" })
|
|
107
|
+
passwordScheme: string;
|
|
108
|
+
// dont send to client
|
|
109
|
+
@Column({ type: "int", default: 1 })
|
|
110
|
+
passwordSchemeVersion: number;
|
|
111
|
+
// dont send to client
|
|
112
|
+
@Column({ type: "timestamp", nullable: true })
|
|
113
|
+
rehashedAt: Date;
|
|
105
114
|
}
|
|
@@ -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 = code === 'unknown-error' ? `${exception?.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
|
|
|
@@ -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 {
|
|
@@ -10,11 +10,10 @@ export interface PasswordFieldOptions {
|
|
|
10
10
|
regexPattern: string | undefined | null;
|
|
11
11
|
fieldName: string | undefined | null;
|
|
12
12
|
isUpdate: Boolean;
|
|
13
|
+
hashingService: HashingService | undefined | null;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export class PasswordFieldCrudManager implements FieldCrudManager {
|
|
16
|
-
private hashingService: HashingService = new BcryptService(); //FIXME: The bcrypt service injected here probably can be optimized to be a singleton
|
|
17
|
-
|
|
18
17
|
constructor(private readonly options: PasswordFieldOptions) {
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -47,7 +46,9 @@ export class PasswordFieldCrudManager implements FieldCrudManager {
|
|
|
47
46
|
|
|
48
47
|
async transformForCreate(dto: any): Promise<any> {
|
|
49
48
|
if(dto[this.options.fieldName]){
|
|
50
|
-
dto[this.options.fieldName] = await this.hashingService.hash(dto[this.options.fieldName]);
|
|
49
|
+
dto[this.options.fieldName] = await this.options.hashingService.hash(dto[this.options.fieldName]);
|
|
50
|
+
dto['passwordScheme'] = this.options.hashingService.name(); //Don't want to expose this in dto // e.g., 'bcrypt'
|
|
51
|
+
dto['passwordHashVersion'] = this.options.hashingService.currentVersion(); //Don't want to expose this in dto // e.g., 1, 2, ...
|
|
51
52
|
}
|
|
52
53
|
return dto;
|
|
53
54
|
}
|
|
@@ -15,7 +15,7 @@ export class LocalStrategy extends PassportStrategy(Strategy) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
async validate(username: string, password: string): Promise<any> {
|
|
18
|
-
const user = await this.authService.
|
|
18
|
+
const user = await this.authService.validateUserAndRehashPasswordIfRequired({ username, password, email: null });
|
|
19
19
|
if (!user) {
|
|
20
20
|
throw new UnauthorizedException();
|
|
21
21
|
}
|
|
@@ -2115,6 +2115,49 @@
|
|
|
2115
2115
|
"relationCreateInverse": true,
|
|
2116
2116
|
"relationModelModuleName": "solid-core",
|
|
2117
2117
|
"isSystem": true
|
|
2118
|
+
},
|
|
2119
|
+
{
|
|
2120
|
+
"name": "passwordScheme",
|
|
2121
|
+
"displayName": "Password Scheme",
|
|
2122
|
+
"type": "selectionStatic",
|
|
2123
|
+
"ormType": "varchar",
|
|
2124
|
+
"length": 256,
|
|
2125
|
+
"required": true,
|
|
2126
|
+
"index": false,
|
|
2127
|
+
"isSystem": true,
|
|
2128
|
+
"columnName": "password_scheme",
|
|
2129
|
+
"defaultValue": "bcrypt",
|
|
2130
|
+
"selectionValueType": "string",
|
|
2131
|
+
"selectionStaticValues": [
|
|
2132
|
+
"bcrypt:bcrypt"
|
|
2133
|
+
]
|
|
2134
|
+
},
|
|
2135
|
+
{
|
|
2136
|
+
"name": "passwordSchemeVersion",
|
|
2137
|
+
"displayName": "Password Scheme Version",
|
|
2138
|
+
"type": "int",
|
|
2139
|
+
"ormType": "integer",
|
|
2140
|
+
"length": 512,
|
|
2141
|
+
"required": true,
|
|
2142
|
+
"defaultValue": 1,
|
|
2143
|
+
"unique": false,
|
|
2144
|
+
"index": false,
|
|
2145
|
+
"private": false,
|
|
2146
|
+
"encrypt": false,
|
|
2147
|
+
"isSystem": true
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
"name": "rehashedAt",
|
|
2151
|
+
"displayName": "Password Rehashed At",
|
|
2152
|
+
"type": "datetime",
|
|
2153
|
+
"ormType": "timestamp",
|
|
2154
|
+
"length": 512,
|
|
2155
|
+
"required": false,
|
|
2156
|
+
"unique": false,
|
|
2157
|
+
"index": false,
|
|
2158
|
+
"private": false,
|
|
2159
|
+
"encrypt": false,
|
|
2160
|
+
"isSystem": true
|
|
2118
2161
|
}
|
|
2119
2162
|
]
|
|
2120
2163
|
},
|
|
@@ -112,6 +112,20 @@ export class AuthenticationService {
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
async updatePasswordDetails(user: User, newPassword: string) {
|
|
116
|
+
user.password = await this.hashingService.hash(newPassword);
|
|
117
|
+
user.passwordScheme = this.hashingService.name();
|
|
118
|
+
user.passwordSchemeVersion = this.hashingService.currentVersion();
|
|
119
|
+
user.rehashedAt = new Date();
|
|
120
|
+
await this.userRepository.update(user.id, {
|
|
121
|
+
password: user.password,
|
|
122
|
+
passwordScheme: user.passwordScheme,
|
|
123
|
+
passwordSchemeVersion: user.passwordSchemeVersion,
|
|
124
|
+
rehashedAt: user.rehashedAt
|
|
125
|
+
});
|
|
126
|
+
return user;
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
async resolveUserByVerificationToken(token: string) {
|
|
116
130
|
return await this.userRepository.findOne({
|
|
117
131
|
where: { verificationTokenOnForgotPassword: token },
|
|
@@ -119,7 +133,7 @@ export class AuthenticationService {
|
|
|
119
133
|
});
|
|
120
134
|
}
|
|
121
135
|
|
|
122
|
-
async
|
|
136
|
+
async validateUserAndRehashPasswordIfRequired(signInDto: SignInDto) {
|
|
123
137
|
|
|
124
138
|
const user = await this.resolveUser(signInDto.username, signInDto.email);
|
|
125
139
|
|
|
@@ -132,11 +146,19 @@ export class AuthenticationService {
|
|
|
132
146
|
const isEqual = await this.hashingService.compare(
|
|
133
147
|
signInDto.password,
|
|
134
148
|
user.password,
|
|
149
|
+
user.passwordSchemeVersion
|
|
135
150
|
);
|
|
136
151
|
if (!isEqual) {
|
|
137
152
|
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
|
|
138
153
|
}
|
|
139
154
|
|
|
155
|
+
// If we reach here means that the user has been validated successfully.
|
|
156
|
+
// Now we check if the password needs to be rehashed based on the current hashing scheme and version.
|
|
157
|
+
if (this.hashingService.needsRehash(user.password, user.passwordSchemeVersion)) {
|
|
158
|
+
const rehashedUser = await this.updatePasswordDetails(user, signInDto.password);
|
|
159
|
+
return rehashedUser;
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
return user;
|
|
141
163
|
}
|
|
142
164
|
|
|
@@ -241,6 +263,8 @@ export class AuthenticationService {
|
|
|
241
263
|
}
|
|
242
264
|
|
|
243
265
|
user.password = pwd;
|
|
266
|
+
user.passwordScheme = this.hashingService.name(); // e.g. bcrypt
|
|
267
|
+
user.passwordSchemeVersion = this.hashingService.currentVersion(); // e.g. 1, 2, 3 ...
|
|
244
268
|
user.active = isUserActive;
|
|
245
269
|
return { user, pwd, autoGeneratedPwd };
|
|
246
270
|
}
|
|
@@ -520,7 +544,7 @@ export class AuthenticationService {
|
|
|
520
544
|
}
|
|
521
545
|
|
|
522
546
|
async signIn(signInDto: SignInDto) {
|
|
523
|
-
const user = await this.
|
|
547
|
+
const user = await this.validateUserAndRehashPasswordIfRequired(signInDto);
|
|
524
548
|
|
|
525
549
|
// TODO: Unset the password etc...
|
|
526
550
|
const tokens = await this.generateTokens(user);
|
|
@@ -720,6 +744,7 @@ export class AuthenticationService {
|
|
|
720
744
|
const isEqual = await this.hashingService.compare(
|
|
721
745
|
changePasswordDto.currentPassword,
|
|
722
746
|
user.password,
|
|
747
|
+
user.passwordSchemeVersion
|
|
723
748
|
);
|
|
724
749
|
if (!isEqual) {
|
|
725
750
|
throw new UnauthorizedException(ERROR_MESSAGES.INCORRECT_CURRENT_PASSWORD);
|
|
@@ -728,6 +753,8 @@ export class AuthenticationService {
|
|
|
728
753
|
// Update Password
|
|
729
754
|
const newPwd = await this.hashingService.hash(changePasswordDto.newPassword);
|
|
730
755
|
user.password = changePasswordDto.newPassword;
|
|
756
|
+
user.passwordScheme = this.hashingService.name(); // e.g. bcrypt
|
|
757
|
+
user.passwordSchemeVersion = this.hashingService.currentVersion(); // e.g. 1, 2, 3 ...
|
|
731
758
|
|
|
732
759
|
// Everytime the user changes the password we reset the forcePasswordChange flag back to false.
|
|
733
760
|
user.forcePasswordChange = false;
|
|
@@ -872,9 +899,11 @@ export class AuthenticationService {
|
|
|
872
899
|
|
|
873
900
|
// 2) Now update the password & history (still inside the same transaction)
|
|
874
901
|
const pwdHash = await this.hashingService.hash(confirmForgotPasswordDto.password);
|
|
902
|
+
const pwdScheme = this.hashingService.name(); // e.g. bcrypt
|
|
903
|
+
const pwdSchemeVersion = this.hashingService.currentVersion(); // e.g. 1, 2, 3 ...
|
|
875
904
|
|
|
876
905
|
// Check reuse with your existing method (ensure it looks at hashes).
|
|
877
|
-
await m.getRepository(User).update({ id: user.id }, { password: pwdHash });
|
|
906
|
+
await m.getRepository(User).update({ id: user.id }, { password: pwdHash, passwordScheme: pwdScheme, passwordSchemeVersion: pwdSchemeVersion});
|
|
878
907
|
this.notifyUserOnPasswordChanged(user);
|
|
879
908
|
|
|
880
909
|
return {
|
|
@@ -1,15 +1,53 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
1
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
2
|
+
import { ConfigType } from '@nestjs/config';
|
|
3
|
+
import { compare as bcryptCompare, genSalt, hash as bcryptHash } from 'bcrypt';
|
|
4
|
+
import { iamConfig } from 'src/config/iam.config';
|
|
2
5
|
import { HashingService } from './hashing.service';
|
|
3
|
-
import { genSalt, hash, compare } from 'bcrypt';
|
|
4
6
|
|
|
5
7
|
@Injectable()
|
|
6
8
|
export class BcryptService implements HashingService {
|
|
9
|
+
constructor(
|
|
10
|
+
@Inject(iamConfig.KEY)
|
|
11
|
+
private readonly iamConfiguration: ConfigType<typeof iamConfig>,
|
|
12
|
+
) { }
|
|
13
|
+
|
|
14
|
+
private readonly rounds = 12;
|
|
15
|
+
private readonly pepper = this.iamConfiguration.passwordPepper ?? '';
|
|
16
|
+
|
|
7
17
|
async hash(data: string | Buffer): Promise<string> {
|
|
8
|
-
const salt = await genSalt();
|
|
9
|
-
|
|
18
|
+
const salt = await genSalt(this.rounds);
|
|
19
|
+
const normalized = this.normalize(data, this.currentVersion());
|
|
20
|
+
return bcryptHash(normalized, salt);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async compare(
|
|
24
|
+
data: string | Buffer,
|
|
25
|
+
hashed: string,
|
|
26
|
+
hashVersion: number = this.currentVersion()
|
|
27
|
+
): Promise<boolean> {
|
|
28
|
+
const normalized = this.normalize(data, hashVersion);
|
|
29
|
+
return bcryptCompare(normalized, hashed);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
needsRehash(_hashed: string, hashVersion: number = this.currentVersion()): boolean {
|
|
33
|
+
return hashVersion < this.currentVersion();
|
|
10
34
|
}
|
|
11
35
|
|
|
12
|
-
|
|
13
|
-
|
|
36
|
+
/** Current hashing policy version (bump when you change rounds/pepper rules) */
|
|
37
|
+
currentVersion(): number {
|
|
38
|
+
return 2;
|
|
14
39
|
}
|
|
15
|
-
|
|
40
|
+
|
|
41
|
+
/** Name of the hashing scheme */
|
|
42
|
+
name(): string {
|
|
43
|
+
return 'bcrypt';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Normalize input based on version & pepper policy */
|
|
47
|
+
private normalize(data: string | Buffer, version: number): string {
|
|
48
|
+
const plain = typeof data === 'string' ? data : data.toString('utf8');
|
|
49
|
+
const usePepper = version >= 2 && this.pepper.length > 0;
|
|
50
|
+
return usePepper ? plain + this.pepper : plain;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
}
|
|
@@ -38,6 +38,7 @@ import { isArray } from "class-validator";
|
|
|
38
38
|
import { ERROR_MESSAGES } from "src/constants/error-messages";
|
|
39
39
|
import { SUCCESS_MESSAGES } from "src/constants/success-messages";
|
|
40
40
|
import { RequestContextService } from "./request-context.service";
|
|
41
|
+
import { HashingService } from "./hashing.service";
|
|
41
42
|
|
|
42
43
|
export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDto, so we get the proper types in our service
|
|
43
44
|
|
|
@@ -307,7 +308,7 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
307
308
|
return new DateFieldCrudManager(options);
|
|
308
309
|
}
|
|
309
310
|
case SolidFieldType.password: {
|
|
310
|
-
const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max, regexPattern: fieldMetadata.regexPattern };
|
|
311
|
+
const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max, regexPattern: fieldMetadata.regexPattern, hashingService: this.moduleRef.get(HashingService, { strict: false }) };
|
|
311
312
|
return new PasswordFieldCrudManager(options);
|
|
312
313
|
}
|
|
313
314
|
case SolidFieldType.mediaSingle:
|