11import {
2- BadRequestException ,
3- HttpException ,
4- Injectable ,
5- InternalServerErrorException ,
6- NestMiddleware ,
7- NotFoundException ,
8- UnauthorizedException ,
2+ BadRequestException ,
3+ HttpException ,
4+ Injectable ,
5+ InternalServerErrorException ,
6+ NestMiddleware ,
7+ NotFoundException ,
8+ UnauthorizedException ,
99} from '@nestjs/common' ;
1010import { InjectRepository } from '@nestjs/typeorm' ;
1111import { UserEntity } from '../entities/user/user.entity.js' ;
@@ -23,93 +23,97 @@ import { IRequestWithCognitoInfo } from './cognito-decoded.interface.js';
2323
2424@Injectable ( )
2525export class AuthWithApiMiddleware implements NestMiddleware {
26- public constructor (
27- @InjectRepository ( UserEntity )
28- private readonly userRepository : Repository < UserEntity > ,
29- ) { }
26+ public constructor (
27+ @InjectRepository ( UserEntity )
28+ private readonly userRepository : Repository < UserEntity > ,
29+ ) { }
3030
31- async use ( req : IRequestWithCognitoInfo , _res : Response , next : ( err ?: any , res ?: any ) => void ) : Promise < void > {
32- try {
33- await this . authenticateRequest ( req ) ;
34- next ( ) ;
35- } catch ( error ) {
36- Sentry . captureException ( error ) ;
37- this . handleAuthenticationError ( error ) ;
38- }
39- }
31+ async use ( req : IRequestWithCognitoInfo , _res : Response , next : ( err ?: any , res ?: any ) => void ) : Promise < void > {
32+ try {
33+ await this . authenticateRequest ( req ) ;
34+ next ( ) ;
35+ } catch ( error ) {
36+ Sentry . captureException ( error ) ;
37+ this . handleAuthenticationError ( error ) ;
38+ }
39+ }
4040
41- private async authenticateRequest ( req : IRequestWithCognitoInfo ) : Promise < void > {
42- const tokenFromCookie = this . getTokenFromCookie ( req ) ;
43- if ( tokenFromCookie ) {
44- await this . authenticateWithToken ( tokenFromCookie , req ) ;
45- } else {
46- await this . authenticateWithApiKey ( req ) ;
47- }
48- }
41+ private async authenticateRequest ( req : IRequestWithCognitoInfo ) : Promise < void > {
42+ const tokenFromCookie = this . getTokenFromCookie ( req ) ;
43+ if ( tokenFromCookie ) {
44+ await this . authenticateWithToken ( tokenFromCookie , req ) ;
45+ } else {
46+ await this . authenticateWithApiKey ( req ) ;
47+ }
48+ }
4949
50- private getTokenFromCookie ( req : Request ) : string | undefined {
51- return req . cookies ?. [ Constants . JWT_COOKIE_KEY_NAME ] ;
52- }
50+ private getTokenFromCookie ( req : Request ) : string | undefined {
51+ return req . cookies ?. [ Constants . JWT_COOKIE_KEY_NAME ] ;
52+ }
5353
54- private handleAuthenticationError ( error : any ) : void {
55- if ( error instanceof HttpException || error instanceof UnauthorizedException ) {
56- throw error ;
57- }
58- throw new InternalServerErrorException ( Messages . AUTHORIZATION_REJECTED ) ;
59- }
54+ private handleAuthenticationError ( error : any ) : void {
55+ if ( error instanceof HttpException || error instanceof UnauthorizedException ) {
56+ throw error ;
57+ }
58+ throw new InternalServerErrorException ( Messages . AUTHORIZATION_REJECTED ) ;
59+ }
6060
61- private async authenticateWithToken ( tokenFromCookie : string , req : IRequestWithCognitoInfo ) : Promise < void > {
62- try {
63- const jwtSecret = process . env . JWT_SECRET ;
64- const data = jwt . verify ( tokenFromCookie , jwtSecret ) as jwt . JwtPayload ;
65- const userId = data . id ;
66- if ( ! userId ) {
67- throw new UnauthorizedException ( 'JWT verification failed' ) ;
68- }
69- const addedScope : Array < JwtScopesEnum > = data . scope ;
70- if ( addedScope && addedScope . length > 0 ) {
71- if ( addedScope . includes ( JwtScopesEnum . TWO_FA_ENABLE ) ) {
72- throw new BadRequestException ( Messages . TWO_FA_REQUIRED ) ;
73- }
74- }
61+ private async authenticateWithToken ( tokenFromCookie : string , req : IRequestWithCognitoInfo ) : Promise < void > {
62+ try {
63+ const jwtSecret = process . env . JWT_SECRET ;
64+ const data = jwt . verify ( tokenFromCookie , jwtSecret ) as jwt . JwtPayload ;
65+ const userId = data . id ;
66+ if ( ! userId ) {
67+ throw new UnauthorizedException ( 'JWT verification failed' ) ;
68+ }
69+ const addedScope : Array < JwtScopesEnum > = data . scope ;
70+ if ( addedScope && addedScope . length > 0 ) {
71+ if ( addedScope . includes ( JwtScopesEnum . TWO_FA_ENABLE ) ) {
72+ throw new BadRequestException ( Messages . TWO_FA_REQUIRED ) ;
73+ }
74+ }
7575
76- const payload = {
77- sub : userId ,
78- email : data . email ,
79- exp : data . exp ,
80- iat : data . iat ,
81- } ;
82- if ( ! payload || isObjectEmpty ( payload ) ) {
83- throw new UnauthorizedException ( 'JWT verification failed' ) ;
84- }
85- req . decoded = payload ;
86- } catch ( error ) {
87- Sentry . captureException ( error ) ;
88- throw error ;
89- }
90- }
76+ const payload = {
77+ sub : userId ,
78+ email : data . email ,
79+ exp : data . exp ,
80+ iat : data . iat ,
81+ } ;
82+ if ( ! payload || isObjectEmpty ( payload ) ) {
83+ throw new UnauthorizedException ( 'JWT verification failed' ) ;
84+ }
85+ req . decoded = payload ;
86+ } catch ( error ) {
87+ Sentry . captureException ( error ) ;
88+ throw error ;
89+ }
90+ }
9191
92- private async authenticateWithApiKey ( req : IRequestWithCognitoInfo ) : Promise < void > {
93- let apiKey = req . headers ?. [ 'x-api-key' ] ;
94- if ( Array . isArray ( apiKey ) ) {
95- apiKey = apiKey [ 0 ] ;
96- }
97- if ( ! apiKey ) {
98- throw new UnauthorizedException ( Messages . NO_AUTH_KEYS_FOUND ) ;
99- }
100- const apiKeyHash = await Encryptor . processDataWithAlgorithm ( apiKey , EncryptionAlgorithmEnum . sha256 ) ;
101- const foundUserByApiKey = await this . userRepository
102- . createQueryBuilder ( 'user' )
103- . innerJoinAndSelect ( 'user.api_keys' , 'api_key' )
104- . where ( 'api_key.hash = :hash' , { hash : apiKeyHash } )
105- . getOne ( ) ;
92+ private async authenticateWithApiKey ( req : IRequestWithCognitoInfo ) : Promise < void > {
93+ let apiKey = req . headers ?. [ 'x-api-key' ] ;
94+ if ( Array . isArray ( apiKey ) ) {
95+ apiKey = apiKey [ 0 ] ;
96+ }
97+ if ( ! apiKey ) {
98+ throw new UnauthorizedException ( Messages . NO_AUTH_KEYS_FOUND ) ;
99+ }
100+ const apiKeyHash = await Encryptor . processDataWithAlgorithm ( apiKey , EncryptionAlgorithmEnum . sha256 ) ;
101+ const foundUserByApiKey = await this . userRepository
102+ . createQueryBuilder ( 'user' )
103+ . innerJoinAndSelect ( 'user.api_keys' , 'api_key' )
104+ . where ( 'api_key.hash = :hash' , { hash : apiKeyHash } )
105+ . getOne ( ) ;
106106
107- if ( ! foundUserByApiKey ) {
108- throw new NotFoundException ( Messages . NO_AUTH_KEYS_FOUND ) ;
109- }
110- req . decoded = {
111- sub : foundUserByApiKey . id ,
112- email : foundUserByApiKey . email ,
113- } ;
114- }
107+ if ( foundUserByApiKey . suspended ) {
108+ throw new UnauthorizedException ( Messages . API_KEY_SUSPENDED ) ;
109+ }
110+
111+ if ( ! foundUserByApiKey ) {
112+ throw new NotFoundException ( Messages . NO_AUTH_KEYS_FOUND ) ;
113+ }
114+ req . decoded = {
115+ sub : foundUserByApiKey . id ,
116+ email : foundUserByApiKey . email ,
117+ } ;
118+ }
115119}
0 commit comments