@lenne.tech/nest-server 9.2.3 → 9.2.4
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/core/common/helpers/input.helper.js +1 -1
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/services/mailjet.service.js +1 -1
- package/dist/core/common/services/mailjet.service.js.map +1 -1
- package/dist/core/modules/auth/auth-guard-strategy.enum.d.ts +4 -0
- package/dist/core/modules/auth/auth-guard-strategy.enum.js +9 -0
- package/dist/core/modules/auth/auth-guard-strategy.enum.js.map +1 -0
- package/dist/core/modules/auth/core-auth.controller.d.ts +18 -0
- package/dist/core/modules/auth/core-auth.controller.js +111 -0
- package/dist/core/modules/auth/core-auth.controller.js.map +1 -0
- package/dist/core/modules/auth/core-auth.module.js +2 -1
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/core-auth.resolver.js +3 -2
- package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
- package/dist/core/modules/auth/exceptions/expired-refresh-token.exception.d.ts +4 -0
- package/dist/core/modules/auth/exceptions/expired-refresh-token.exception.js +11 -0
- package/dist/core/modules/auth/exceptions/expired-refresh-token.exception.js.map +1 -0
- package/dist/core/modules/auth/exceptions/expired-token.exception.d.ts +4 -0
- package/dist/core/modules/auth/exceptions/expired-token.exception.js +11 -0
- package/dist/core/modules/auth/exceptions/expired-token.exception.js.map +1 -0
- package/dist/core/modules/auth/exceptions/invalid-token.exception.d.ts +4 -0
- package/dist/core/modules/auth/exceptions/invalid-token.exception.js +11 -0
- package/dist/core/modules/auth/exceptions/invalid-token.exception.js.map +1 -0
- package/dist/core/modules/auth/guards/auth.guard.d.ts +2 -1
- package/dist/core/modules/auth/guards/auth.guard.js +14 -6
- package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +3 -2
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth.service.js +10 -8
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/auth/strategies/jwt-refresh.strategy.js +2 -1
- package/dist/core/modules/auth/strategies/jwt-refresh.strategy.js.map +1 -1
- package/dist/core/modules/auth/strategies/jwt.strategy.js +2 -1
- package/dist/core/modules/auth/strategies/jwt.strategy.js.map +1 -1
- package/dist/core/modules/file/core-file.service.js +1 -1
- package/dist/core/modules/file/core-file.service.js.map +1 -1
- package/dist/core/modules/user/core-user.service.js +3 -3
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core.module.js +2 -2
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/auth/auth.controller.d.ts +8 -0
- package/dist/server/modules/auth/auth.controller.js +30 -0
- package/dist/server/modules/auth/auth.controller.js.map +1 -0
- package/dist/server/modules/file/file.controller.js +3 -3
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/common/helpers/input.helper.ts +2 -2
- package/src/core/common/services/mailjet.service.ts +2 -2
- package/src/core/modules/auth/auth-guard-strategy.enum.ts +4 -0
- package/src/core/modules/auth/core-auth.controller.ts +110 -0
- package/src/core/modules/auth/core-auth.module.ts +2 -1
- package/src/core/modules/auth/core-auth.resolver.ts +3 -2
- package/src/core/modules/auth/exceptions/expired-refresh-token.exception.ts +10 -0
- package/src/core/modules/auth/exceptions/expired-token.exception.ts +10 -0
- package/src/core/modules/auth/exceptions/invalid-token.exception.ts +10 -0
- package/src/core/modules/auth/guards/auth.guard.ts +14 -6
- package/src/core/modules/auth/guards/roles.guard.ts +3 -2
- package/src/core/modules/auth/services/core-auth.service.ts +10 -10
- package/src/core/modules/auth/strategies/jwt-refresh.strategy.ts +3 -3
- package/src/core/modules/auth/strategies/jwt.strategy.ts +2 -1
- package/src/core/modules/file/core-file.service.ts +1 -1
- package/src/core/modules/user/core-user.service.ts +3 -5
- package/src/core.module.ts +2 -2
- package/src/index.ts +5 -0
- package/src/server/modules/auth/auth.controller.ts +17 -0
- package/src/server/modules/file/file.controller.ts +4 -3
- package/src/server/modules/user/user.service.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.4",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
|
|
1
|
+
import { BadRequestException, HttpException, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { plainToInstance } from 'class-transformer';
|
|
3
3
|
import { validate } from 'class-validator';
|
|
4
4
|
import { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions';
|
|
@@ -362,7 +362,7 @@ export function deepFreeze(object: any) {
|
|
|
362
362
|
* Standard error function
|
|
363
363
|
*/
|
|
364
364
|
export function errorFunction(caller: (...params) => any, message = 'Required parameter is missing or invalid') {
|
|
365
|
-
const err = new
|
|
365
|
+
const err = new BadRequestException(message);
|
|
366
366
|
Error.captureStackTrace(err, caller);
|
|
367
367
|
throw err;
|
|
368
368
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
1
|
+
import { HttpException, Injectable } from '@nestjs/common';
|
|
2
2
|
import { template } from 'lodash';
|
|
3
3
|
import { ConfigService } from './config.service';
|
|
4
4
|
// eslint-disable-next-line
|
|
@@ -86,7 +86,7 @@ export class MailjetService {
|
|
|
86
86
|
this.configService.getFastButReadOnly('email.mailjet.api_key_public') &&
|
|
87
87
|
this.configService.getFastButReadOnly('email.mailjet.api_key_private')
|
|
88
88
|
) {
|
|
89
|
-
throw new
|
|
89
|
+
throw new HttpException('Cannot connect to mailjet.', 502);
|
|
90
90
|
}
|
|
91
91
|
console.debug(
|
|
92
92
|
JSON.stringify(
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Body, Controller, Get, Param, ParseBoolPipe, Post, Res, UseGuards } from '@nestjs/common';
|
|
2
|
+
import { Args, Info } from '@nestjs/graphql';
|
|
3
|
+
import { Response as ResponseType } from 'express';
|
|
4
|
+
import { GraphQLResolveInfo } from 'graphql/index';
|
|
5
|
+
import { GraphQLUser } from '../../common/decorators/graphql-user.decorator';
|
|
6
|
+
import { RESTUser } from '../../common/decorators/rest-user.decorator';
|
|
7
|
+
import { ConfigService } from '../../common/services/config.service';
|
|
8
|
+
import { AuthGuardStrategy } from './auth-guard-strategy.enum';
|
|
9
|
+
import { CoreAuthModel } from './core-auth.model';
|
|
10
|
+
import { AuthGuard } from './guards/auth.guard';
|
|
11
|
+
import { CoreAuthSignInInput } from './inputs/core-auth-sign-in.input';
|
|
12
|
+
import { CoreAuthSignUpInput } from './inputs/core-auth-sign-up.input';
|
|
13
|
+
import { ICoreAuthUser } from './interfaces/core-auth-user.interface';
|
|
14
|
+
import { CoreAuthService } from './services/core-auth.service';
|
|
15
|
+
import { Tokens } from './tokens.decorator';
|
|
16
|
+
|
|
17
|
+
@Controller('auth')
|
|
18
|
+
export class CoreAuthController {
|
|
19
|
+
/**
|
|
20
|
+
* Import services
|
|
21
|
+
*/
|
|
22
|
+
constructor(protected readonly authService: CoreAuthService, protected readonly configService: ConfigService) {}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Logout user (from specific device)
|
|
26
|
+
*/
|
|
27
|
+
@UseGuards(AuthGuard(AuthGuardStrategy.JWT))
|
|
28
|
+
@Get()
|
|
29
|
+
async logout(
|
|
30
|
+
@RESTUser() currentUser: ICoreAuthUser,
|
|
31
|
+
@Tokens('token') token: string,
|
|
32
|
+
@Res() res: ResponseType,
|
|
33
|
+
@Param('allDevices', ParseBoolPipe) allDevices?: boolean
|
|
34
|
+
): Promise<boolean> {
|
|
35
|
+
const result = await this.authService.logout(token, { currentUser, allDevices });
|
|
36
|
+
return this.processCookies(res, result);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Refresh token (for specific device)
|
|
41
|
+
*/
|
|
42
|
+
@UseGuards(AuthGuard(AuthGuardStrategy.JWT_REFRESH))
|
|
43
|
+
@Get()
|
|
44
|
+
async refreshToken(
|
|
45
|
+
@GraphQLUser() user: ICoreAuthUser,
|
|
46
|
+
@Tokens('refreshToken') refreshToken: string,
|
|
47
|
+
@Res() res: ResponseType
|
|
48
|
+
): Promise<CoreAuthModel> {
|
|
49
|
+
const result = await this.authService.refreshTokens(user, refreshToken);
|
|
50
|
+
return this.processCookies(res, result);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Sign in user via email and password (on specific device)
|
|
55
|
+
*/
|
|
56
|
+
@Post()
|
|
57
|
+
async signIn(
|
|
58
|
+
@Info() info: GraphQLResolveInfo,
|
|
59
|
+
@Res() res: ResponseType,
|
|
60
|
+
@Body('input') input: CoreAuthSignInInput
|
|
61
|
+
): Promise<CoreAuthModel> {
|
|
62
|
+
const result = await this.authService.signIn(input);
|
|
63
|
+
return this.processCookies(res, result);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Register a new user account (on specific device)
|
|
68
|
+
*/
|
|
69
|
+
@Post()
|
|
70
|
+
async signUp(
|
|
71
|
+
@Info() info: GraphQLResolveInfo,
|
|
72
|
+
@Res() res: ResponseType,
|
|
73
|
+
@Args('input') input: CoreAuthSignUpInput
|
|
74
|
+
): Promise<CoreAuthModel> {
|
|
75
|
+
const result = await this.authService.signUp(input);
|
|
76
|
+
return this.processCookies(res, result);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ===================================================================================================================
|
|
80
|
+
// Helper
|
|
81
|
+
// ===================================================================================================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Process cookies
|
|
85
|
+
*/
|
|
86
|
+
protected processCookies(res: ResponseType, result: any) {
|
|
87
|
+
// Check if cookie handling is activated
|
|
88
|
+
if (this.configService.getFastButReadOnly('cookies')) {
|
|
89
|
+
// Set cookies
|
|
90
|
+
if (typeof result !== 'object') {
|
|
91
|
+
res.cookie('token', '', { httpOnly: true });
|
|
92
|
+
res.cookie('refreshToken', '', { httpOnly: true });
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
res.cookie('token', result?.token || '', { httpOnly: true });
|
|
96
|
+
res.cookie('refreshToken', result?.refreshToken || '', { httpOnly: true });
|
|
97
|
+
|
|
98
|
+
// Remove tokens from result
|
|
99
|
+
if (result.token) {
|
|
100
|
+
delete result.token;
|
|
101
|
+
}
|
|
102
|
+
if (result.refreshToken) {
|
|
103
|
+
delete result.refreshToken;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Return prepared result
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -2,6 +2,7 @@ import { DynamicModule, ForwardReference, Module, Provider, Type } from '@nestjs
|
|
|
2
2
|
import { APP_GUARD } from '@nestjs/core';
|
|
3
3
|
import { JwtModule, JwtModuleOptions } from '@nestjs/jwt';
|
|
4
4
|
import { PassportModule } from '@nestjs/passport';
|
|
5
|
+
import { AuthGuardStrategy } from './auth-guard-strategy.enum';
|
|
5
6
|
import { RolesGuard } from './guards/roles.guard';
|
|
6
7
|
import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy';
|
|
7
8
|
import { JwtStrategy } from './strategies/jwt.strategy';
|
|
@@ -32,7 +33,7 @@ export class CoreAuthModule {
|
|
|
32
33
|
// Process imports
|
|
33
34
|
let imports: any[] = [
|
|
34
35
|
UserModule,
|
|
35
|
-
PassportModule.register({ defaultStrategy: [
|
|
36
|
+
PassportModule.register({ defaultStrategy: [AuthGuardStrategy.JWT, AuthGuardStrategy.JWT_REFRESH] }),
|
|
36
37
|
JwtModule.register(options),
|
|
37
38
|
];
|
|
38
39
|
if (Array.isArray(options?.imports)) {
|
|
@@ -4,6 +4,7 @@ import { Response as ResponseType } from 'express';
|
|
|
4
4
|
import { GraphQLResolveInfo } from 'graphql';
|
|
5
5
|
import { GraphQLUser } from '../../common/decorators/graphql-user.decorator';
|
|
6
6
|
import { ConfigService } from '../../common/services/config.service';
|
|
7
|
+
import { AuthGuardStrategy } from './auth-guard-strategy.enum';
|
|
7
8
|
import { CoreAuthModel } from './core-auth.model';
|
|
8
9
|
import { AuthGuard } from './guards/auth.guard';
|
|
9
10
|
import { CoreAuthSignInInput } from './inputs/core-auth-sign-in.input';
|
|
@@ -29,7 +30,7 @@ export class CoreAuthResolver {
|
|
|
29
30
|
/**
|
|
30
31
|
* Logout user (from specific device)
|
|
31
32
|
*/
|
|
32
|
-
@UseGuards(AuthGuard(
|
|
33
|
+
@UseGuards(AuthGuard(AuthGuardStrategy.JWT))
|
|
33
34
|
@Mutation((returns) => Boolean, { description: 'Logout user (from specific device)' })
|
|
34
35
|
async logout(
|
|
35
36
|
@GraphQLUser() currentUser: ICoreAuthUser,
|
|
@@ -44,7 +45,7 @@ export class CoreAuthResolver {
|
|
|
44
45
|
/**
|
|
45
46
|
* Refresh token (for specific device)
|
|
46
47
|
*/
|
|
47
|
-
@UseGuards(AuthGuard(
|
|
48
|
+
@UseGuards(AuthGuard(AuthGuardStrategy.JWT_REFRESH))
|
|
48
49
|
@Mutation((returns) => CoreAuthModel, { description: 'Refresh tokens (for specific device)' })
|
|
49
50
|
async refreshToken(
|
|
50
51
|
@GraphQLUser() user: ICoreAuthUser,
|
|
@@ -5,6 +5,10 @@ import { defaultOptions } from '@nestjs/passport/dist/options';
|
|
|
5
5
|
import { memoize } from '@nestjs/passport/dist/utils/memoize.util';
|
|
6
6
|
import * as jwt from 'jsonwebtoken';
|
|
7
7
|
import * as passport from 'passport';
|
|
8
|
+
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
9
|
+
import { ExpiredRefreshTokenException } from '../exceptions/expired-refresh-token.exception';
|
|
10
|
+
import { ExpiredTokenException } from '../exceptions/expired-token.exception';
|
|
11
|
+
import { InvalidTokenException } from '../exceptions/invalid-token.exception';
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
14
|
* Missing strategy error
|
|
@@ -105,13 +109,17 @@ function createAuthGuard(type?: string): Type<CanActivate> {
|
|
|
105
109
|
*/
|
|
106
110
|
handleRequest(err, user, info, context): TUser {
|
|
107
111
|
if (err) {
|
|
108
|
-
|
|
109
|
-
throw new UnauthorizedException('Invalid token');
|
|
110
|
-
}
|
|
111
|
-
throw err;
|
|
112
|
+
throw new InvalidTokenException();
|
|
112
113
|
}
|
|
113
114
|
if (!user) {
|
|
114
|
-
|
|
115
|
+
if (info?.name === 'TokenExpiredError') {
|
|
116
|
+
if (type === AuthGuardStrategy.JWT_REFRESH) {
|
|
117
|
+
throw new ExpiredRefreshTokenException();
|
|
118
|
+
} else {
|
|
119
|
+
throw new ExpiredTokenException();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
throw new InvalidTokenException();
|
|
115
123
|
}
|
|
116
124
|
return user;
|
|
117
125
|
}
|
|
@@ -124,4 +132,4 @@ function createAuthGuard(type?: string): Type<CanActivate> {
|
|
|
124
132
|
/**
|
|
125
133
|
* Export AuthGuard
|
|
126
134
|
*/
|
|
127
|
-
export const AuthGuard: (type?: string | string[]) => Type<IAuthGuard> = memoize(createAuthGuard);
|
|
135
|
+
export const AuthGuard: (type?: string | string[] | AuthGuardStrategy) => Type<IAuthGuard> = memoize(createAuthGuard);
|
|
@@ -2,6 +2,7 @@ import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/com
|
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
4
4
|
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
5
|
+
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
5
6
|
import { AuthGuard } from './auth.guard';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -12,7 +13,7 @@ import { AuthGuard } from './auth.guard';
|
|
|
12
13
|
* If this is not the case, an UnauthorizedException is thrown.
|
|
13
14
|
*/
|
|
14
15
|
@Injectable()
|
|
15
|
-
export class RolesGuard extends AuthGuard(
|
|
16
|
+
export class RolesGuard extends AuthGuard(AuthGuardStrategy.JWT) {
|
|
16
17
|
/**
|
|
17
18
|
* Integrate reflector
|
|
18
19
|
*/
|
|
@@ -53,7 +54,7 @@ export class RolesGuard extends AuthGuard('jwt') {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
// Requester is not authorized
|
|
56
|
-
throw new UnauthorizedException();
|
|
57
|
+
throw new UnauthorizedException('Missing role');
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
// Everything is ok
|
|
@@ -45,13 +45,13 @@ export class CoreAuthService {
|
|
|
45
45
|
// Check authentication
|
|
46
46
|
const user = serviceOptions.currentUser;
|
|
47
47
|
if (!user || !tokenOrRefreshToken) {
|
|
48
|
-
throw new UnauthorizedException();
|
|
48
|
+
throw new UnauthorizedException('Invalid token');
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// Check authorization
|
|
52
52
|
const deviceId = this.decodeJwt(tokenOrRefreshToken)?.deviceId;
|
|
53
53
|
if (!deviceId || !user.refreshTokens[deviceId]) {
|
|
54
|
-
throw new UnauthorizedException('Invalid
|
|
54
|
+
throw new UnauthorizedException('Invalid token');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
// Logout from all devices
|
|
@@ -101,11 +101,11 @@ export class CoreAuthService {
|
|
|
101
101
|
|
|
102
102
|
// Get user
|
|
103
103
|
const user = await this.userService.getViaEmail(email, serviceOptionsForUserService);
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
) {
|
|
108
|
-
throw new UnauthorizedException();
|
|
104
|
+
if (!user) {
|
|
105
|
+
throw new UnauthorizedException('Unknown email');
|
|
106
|
+
}
|
|
107
|
+
if (!((await bcrypt.compare(password, user.password)) || (await bcrypt.compare(sha256(password), user.password)))) {
|
|
108
|
+
throw new UnauthorizedException('Wrong password');
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// Return tokens and user
|
|
@@ -125,7 +125,7 @@ export class CoreAuthService {
|
|
|
125
125
|
// Get and check user
|
|
126
126
|
const user = await this.userService.create(input, serviceOptionsForUserService);
|
|
127
127
|
if (!user) {
|
|
128
|
-
throw new BadRequestException('Email
|
|
128
|
+
throw new BadRequestException('Email address already in use');
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
// Set device ID
|
|
@@ -233,7 +233,7 @@ export class CoreAuthService {
|
|
|
233
233
|
if (currentRefreshToken) {
|
|
234
234
|
deviceId = this.decodeJwt(currentRefreshToken)?.deviceId;
|
|
235
235
|
if (!deviceId || !user.refreshTokens?.[deviceId]) {
|
|
236
|
-
throw new UnauthorizedException('Invalid
|
|
236
|
+
throw new UnauthorizedException('Invalid token');
|
|
237
237
|
}
|
|
238
238
|
if (!this.configService.getFastButReadOnly('jwt.refresh.renewal')) {
|
|
239
239
|
// Return currentToken
|
|
@@ -254,7 +254,7 @@ export class CoreAuthService {
|
|
|
254
254
|
// Set new token
|
|
255
255
|
const payload = this.decodeJwt(newRefreshToken);
|
|
256
256
|
if (!payload) {
|
|
257
|
-
throw new UnauthorizedException();
|
|
257
|
+
throw new UnauthorizedException('Invalid token');
|
|
258
258
|
}
|
|
259
259
|
if (!deviceId) {
|
|
260
260
|
deviceId = payload.deviceId;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { PassportStrategy } from '@nestjs/passport';
|
|
3
|
-
import * as bcrypt from 'bcrypt';
|
|
4
3
|
import { Request as RequestType, Request } from 'express';
|
|
5
4
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
6
5
|
import { ConfigService } from '../../../common/services/config.service';
|
|
6
|
+
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
7
7
|
import { CoreAuthService } from '../services/core-auth.service';
|
|
8
8
|
|
|
9
9
|
@Injectable()
|
|
10
|
-
export class JwtRefreshStrategy extends PassportStrategy(Strategy,
|
|
10
|
+
export class JwtRefreshStrategy extends PassportStrategy(Strategy, AuthGuardStrategy.JWT_REFRESH) {
|
|
11
11
|
constructor(protected readonly authService: CoreAuthService, protected readonly configService: ConfigService) {
|
|
12
12
|
super({
|
|
13
13
|
jwtFromRequest: ExtractJwt.fromExtractors([
|
|
@@ -2,6 +2,7 @@ import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
|
2
2
|
import { PassportStrategy } from '@nestjs/passport';
|
|
3
3
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
4
4
|
import { ConfigService } from '../../../common/services/config.service';
|
|
5
|
+
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
5
6
|
import { JwtPayload } from '../interfaces/jwt-payload.interface';
|
|
6
7
|
import { CoreAuthService } from '../services/core-auth.service';
|
|
7
8
|
import { Request as RequestType } from 'express';
|
|
@@ -10,7 +11,7 @@ import { Request as RequestType } from 'express';
|
|
|
10
11
|
* Use JWT strategy for passport
|
|
11
12
|
*/
|
|
12
13
|
@Injectable()
|
|
13
|
-
export class JwtStrategy extends PassportStrategy(Strategy,
|
|
14
|
+
export class JwtStrategy extends PassportStrategy(Strategy, AuthGuardStrategy.JWT) {
|
|
14
15
|
/**
|
|
15
16
|
* Init JWT strategy
|
|
16
17
|
*/
|
|
@@ -72,7 +72,7 @@ export abstract class CoreFileService {
|
|
|
72
72
|
const filterQuery = convertFilterArgsToQuery(filterArgs);
|
|
73
73
|
const cursor = this.files.find(filterQuery[0], filterQuery[1]);
|
|
74
74
|
if (!cursor) {
|
|
75
|
-
throw new
|
|
75
|
+
throw new NotFoundException('File collection not found');
|
|
76
76
|
}
|
|
77
77
|
cursor.toArray((error, docs) => {
|
|
78
78
|
error ? reject(error) : resolve(this.prepareOutput(docs, serviceOptions));
|
|
@@ -55,9 +55,7 @@ export abstract class CoreUserService<
|
|
|
55
55
|
await createdUser.save();
|
|
56
56
|
} catch (error) {
|
|
57
57
|
if (error.code === 11000) {
|
|
58
|
-
throw new
|
|
59
|
-
`User with email address "${(data.input as any).email}" already exists`
|
|
60
|
-
);
|
|
58
|
+
throw new BadRequestException('Email address already in use');
|
|
61
59
|
} else {
|
|
62
60
|
throw new UnprocessableEntityException();
|
|
63
61
|
}
|
|
@@ -105,7 +103,7 @@ export abstract class CoreUserService<
|
|
|
105
103
|
}
|
|
106
104
|
|
|
107
105
|
if (!dbObject.verificationToken) {
|
|
108
|
-
throw new
|
|
106
|
+
throw new BadRequestException('User has no verification token');
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
if (dbObject.verified) {
|
|
@@ -185,7 +183,7 @@ export abstract class CoreUserService<
|
|
|
185
183
|
|
|
186
184
|
// Check roles values
|
|
187
185
|
if (roles.some((role) => typeof role !== 'string')) {
|
|
188
|
-
throw new BadRequestException('
|
|
186
|
+
throw new BadRequestException('Roles contains invalid values');
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
// Update and return user
|
package/src/core.module.ts
CHANGED
|
@@ -78,7 +78,7 @@ export class CoreModule implements NestModule {
|
|
|
78
78
|
return { user: user, headers: connectionParams };
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
throw new UnauthorizedException();
|
|
81
|
+
throw new UnauthorizedException('Missing authentication token');
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
84
|
},
|
|
@@ -98,7 +98,7 @@ export class CoreModule implements NestModule {
|
|
|
98
98
|
return extra;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
throw new UnauthorizedException();
|
|
101
|
+
throw new UnauthorizedException('Missing authentication token');
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
context: ({ extra }) => extra,
|
package/src/index.ts
CHANGED
|
@@ -76,6 +76,9 @@ export * from './core/common/types/string-or-object-id.type';
|
|
|
76
76
|
// Core - Modules - Auth
|
|
77
77
|
// =====================================================================================================================
|
|
78
78
|
|
|
79
|
+
export * from './core/modules/auth/exceptions/expired-refresh-token.exception';
|
|
80
|
+
export * from './core/modules/auth/exceptions/expired-token.exception';
|
|
81
|
+
export * from './core/modules/auth/exceptions/invalid-token.exception';
|
|
79
82
|
export * from './core/modules/auth/guards/auth.guard';
|
|
80
83
|
export * from './core/modules/auth/guards/roles.guard';
|
|
81
84
|
export * from './core/modules/auth/inputs/core-auth-sign-in.input';
|
|
@@ -87,6 +90,8 @@ export * from './core/modules/auth/services/core-auth.service';
|
|
|
87
90
|
export * from './core/modules/auth/services/core-auth-user.service';
|
|
88
91
|
export * from './core/modules/auth/strategies/jwt.strategy';
|
|
89
92
|
export * from './core/modules/auth/strategies/jwt-refresh.strategy';
|
|
93
|
+
export * from './core/modules/auth/auth-guard-strategy.enum';
|
|
94
|
+
export * from './core/modules/auth/core-auth.controller';
|
|
90
95
|
export * from './core/modules/auth/core-auth.model';
|
|
91
96
|
export * from './core/modules/auth/core-auth.module';
|
|
92
97
|
export * from './core/modules/auth/core-auth.resolver';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Controller } from '@nestjs/common';
|
|
2
|
+
import { ConfigService } from '../../../core/common/services/config.service';
|
|
3
|
+
import { CoreAuthController } from '../../../core/modules/auth/core-auth.controller';
|
|
4
|
+
import { AuthService } from './auth.service';
|
|
5
|
+
|
|
6
|
+
@Controller('auth')
|
|
7
|
+
export class AuthController extends CoreAuthController {
|
|
8
|
+
/**
|
|
9
|
+
* Import project services
|
|
10
|
+
*/
|
|
11
|
+
constructor(
|
|
12
|
+
protected override readonly authService: AuthService,
|
|
13
|
+
protected override readonly configService: ConfigService
|
|
14
|
+
) {
|
|
15
|
+
super(authService, configService);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BadRequestException,
|
|
2
3
|
Controller,
|
|
3
4
|
Delete,
|
|
4
5
|
Get,
|
|
@@ -41,7 +42,7 @@ export class FileController {
|
|
|
41
42
|
@Get(':id')
|
|
42
43
|
async getFile(@Param('id') id: string, @Res() res) {
|
|
43
44
|
if (!id) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new BadRequestException('Missing ID');
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
let file;
|
|
@@ -52,7 +53,7 @@ export class FileController {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
if (!file) {
|
|
55
|
-
throw new NotFoundException();
|
|
56
|
+
throw new NotFoundException('File not found');
|
|
56
57
|
}
|
|
57
58
|
const filestream = await this.fileService.getFileStream(id);
|
|
58
59
|
res.header('Content-Type', file.contentType);
|
|
@@ -75,7 +76,7 @@ export class FileController {
|
|
|
75
76
|
@Delete(':id')
|
|
76
77
|
async deleteFile(@Param('id') id: string) {
|
|
77
78
|
if (!id) {
|
|
78
|
-
throw new
|
|
79
|
+
throw new BadRequestException('Missing ID');
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
return await this.fileService.deleteFile(id);
|
|
@@ -88,7 +88,7 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
|
|
|
88
88
|
const dbUser = await this.mainDbModel.findOne({ id: user.id }).exec();
|
|
89
89
|
// Check user
|
|
90
90
|
if (!dbUser) {
|
|
91
|
-
throw new UnauthorizedException();
|
|
91
|
+
throw new UnauthorizedException('User is not allowed to set the avatar');
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// Check file
|