From 9993c63a56f7ae4a07bf1a1650ec99b58381c2b7 Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Mon, 3 Jun 2024 09:06:55 +0200 Subject: [PATCH] clean up --- backend/src/app.module.ts | 7 +- .../src/modules/auth-module/auth.module.ts | 3 - .../decorators/get-user-id.decorator.ts | 11 - .../common/decorators/get-user.decorator.ts | 13 -- .../auth-module/common/decorators/index.ts | 2 - .../auth-module/common/guards/index.ts | 2 - .../common/guards/refresh-token.guard.ts | 7 - .../auth-module/controller/auth.controller.ts | 84 +++----- .../repositories/session.repository.ts | 9 + .../auth-module/services/auth.service.ts | 199 +++++++++--------- .../auth-module/services/session.service.ts | 4 + .../strategies/access-token.strategie.ts | 27 --- .../modules/auth-module/strategies/index.ts | 2 - .../strategies/refresh-token.strategie.ts | 39 ---- 14 files changed, 145 insertions(+), 264 deletions(-) delete mode 100644 backend/src/modules/auth-module/common/decorators/get-user-id.decorator.ts delete mode 100644 backend/src/modules/auth-module/common/decorators/get-user.decorator.ts delete mode 100644 backend/src/modules/auth-module/common/guards/refresh-token.guard.ts delete mode 100644 backend/src/modules/auth-module/strategies/access-token.strategie.ts delete mode 100644 backend/src/modules/auth-module/strategies/refresh-token.strategie.ts diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index aebae39..c47ea88 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -10,7 +10,6 @@ import { CspMiddleware } from './middleware/csp-middleware/csp.middleware'; import { HttpsRedirectMiddleware } from './middleware/https-middlware/https-redirect.middleware'; import { SecurityHeadersMiddleware } from './middleware/security-middleware/security.middleware'; import { AuthModule } from './modules/auth-module/auth.module'; -import { AccessTokenGuard } from './modules/auth-module/common/guards'; import { DatabaseModule } from './modules/database-module/database.module'; import { SendgridModule } from './modules/sendgrid-module/sendgrid.module'; import { UserModule } from './modules/user-module/user.module'; @@ -29,11 +28,7 @@ import { VerifyModule } from './modules/verify-module/verify.module'; VerifyModule, ], controllers: [AppController], - providers: [ - AppService, - { provide: 'APP_GUARD', useClass: AccessTokenGuard }, - ClearExpiredSessionsCron, - ], + providers: [AppService, ClearExpiredSessionsCron], }) export class AppModule { public configure(consumer: MiddlewareConsumer): void { diff --git a/backend/src/modules/auth-module/auth.module.ts b/backend/src/modules/auth-module/auth.module.ts index fa74b66..f62de82 100644 --- a/backend/src/modules/auth-module/auth.module.ts +++ b/backend/src/modules/auth-module/auth.module.ts @@ -13,7 +13,6 @@ import { UserCredentialsRepository } from './repositories/user-credentials.repos import { AuthService } from './services/auth.service'; import { SessionService } from './services/session.service'; import { TokenManagementService } from './services/token-management.service'; -import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; @Module({ imports: [ @@ -29,8 +28,6 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; TokenManagementService, UserCredentialsRepository, SessionRepository, - AccessTokenStrategy, - RefreshTokenStrategy, ], controllers: [AuthController], exports: [SessionService], diff --git a/backend/src/modules/auth-module/common/decorators/get-user-id.decorator.ts b/backend/src/modules/auth-module/common/decorators/get-user-id.decorator.ts deleted file mode 100644 index 4a82dc5..0000000 --- a/backend/src/modules/auth-module/common/decorators/get-user-id.decorator.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createParamDecorator, ExecutionContext } from '@nestjs/common'; -import { JwtPayload } from 'src/modules/auth-module/models/types'; - -export const GetCurrentUserId = createParamDecorator( - (_: undefined, context: ExecutionContext): number => { - const request = context.switchToHttp().getRequest(); - const user = request.user as JwtPayload; - - return user.sub; - } -); diff --git a/backend/src/modules/auth-module/common/decorators/get-user.decorator.ts b/backend/src/modules/auth-module/common/decorators/get-user.decorator.ts deleted file mode 100644 index f03ed49..0000000 --- a/backend/src/modules/auth-module/common/decorators/get-user.decorator.ts +++ /dev/null @@ -1,13 +0,0 @@ -//import { JwtPayloadWithRefreshToken } from 'src/modules/auth-module/models/types'; - -// export const GetCurrentUser = createParamDecorator( -// ( -// data: keyof JwtPayloadWithRefreshToken | undefined, -// context: ExecutionContext -// ) => { -// const request = context.switchToHttp().getRequest(); - -// if (!data) return request.user; -// return request.user[data]; -// } -// ); diff --git a/backend/src/modules/auth-module/common/decorators/index.ts b/backend/src/modules/auth-module/common/decorators/index.ts index 6e85616..e69de29 100644 --- a/backend/src/modules/auth-module/common/decorators/index.ts +++ b/backend/src/modules/auth-module/common/decorators/index.ts @@ -1,2 +0,0 @@ -export * from './get-user-id.decorator'; -// export * from './get-user.decorator'; diff --git a/backend/src/modules/auth-module/common/guards/index.ts b/backend/src/modules/auth-module/common/guards/index.ts index 50511b9..e69de29 100644 --- a/backend/src/modules/auth-module/common/guards/index.ts +++ b/backend/src/modules/auth-module/common/guards/index.ts @@ -1,2 +0,0 @@ -export * from './access-token.guard'; -export * from './refresh-token.guard'; diff --git a/backend/src/modules/auth-module/common/guards/refresh-token.guard.ts b/backend/src/modules/auth-module/common/guards/refresh-token.guard.ts deleted file mode 100644 index e9b853f..0000000 --- a/backend/src/modules/auth-module/common/guards/refresh-token.guard.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AuthGuard } from '@nestjs/passport'; - -export class RefreshTokenGuard extends AuthGuard('jwt-refresh-token') { - public constructor() { - super(); - } -} diff --git a/backend/src/modules/auth-module/controller/auth.controller.ts b/backend/src/modules/auth-module/controller/auth.controller.ts index c4c96e6..fbd7caa 100644 --- a/backend/src/modules/auth-module/controller/auth.controller.ts +++ b/backend/src/modules/auth-module/controller/auth.controller.ts @@ -1,22 +1,8 @@ -import { - Controller, - Post, - Body, - HttpCode, - HttpStatus, - Res, - Req, -} from '@nestjs/common'; +import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common'; import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger'; -import { Response, Request } from 'express'; import { Public } from 'src/shared/decorator'; -import { GetCurrentUserId } from '../common/decorators'; -import { - AccessTokenDto, - LoginResponseDto, - UserCredentialsDto, -} from '../models/dto'; +import { LoginResponseDto, UserCredentialsDto } from '../models/dto'; import { AuthService } from '../services/auth.service'; @ApiTags('Authentication') @@ -37,39 +23,39 @@ export class AuthController { return this.authService.signup(userCredentials); } - @ApiCreatedResponse({ - description: 'User signin successfully', - type: LoginResponseDto, - }) - @HttpCode(HttpStatus.OK) - @Public() - @Post('signin') - public async signin( - @Res({ passthrough: true }) response: Response, - @Req() request: Request, - @Body() userCredentials: UserCredentialsDto - ): Promise { - return await this.authService.signin(userCredentials, response, request); - } + // @ApiCreatedResponse({ + // description: 'User signin successfully', + // type: LoginResponseDto, + // }) + // @HttpCode(HttpStatus.OK) + // @Public() + // @Post('signin') + // public async signin( + // @Res({ passthrough: true }) response: Response, + // @Req() request: Request, + // @Body() userCredentials: UserCredentialsDto + // ): Promise { + // return await this.authService.signin(userCredentials, response, request); + // } - @ApiCreatedResponse({ - description: 'User tokens refreshed successfully', - type: AccessTokenDto, - }) - @HttpCode(HttpStatus.OK) - @Public() - @Post('refresh') - public async refreshToken(@Req() request: Request): Promise { - return await this.authService.refresh(request); - } + // @ApiCreatedResponse({ + // description: 'User tokens refreshed successfully', + // type: AccessTokenDto, + // }) + // @HttpCode(HttpStatus.OK) + // @Public() + // @Post('refresh') + // public async refreshToken(@Req() request: Request): Promise { + // return await this.authService.refresh(request); + // } - @ApiCreatedResponse({ - description: 'User signed out successfully', - type: Boolean, - }) - @HttpCode(HttpStatus.OK) - @Post('logout') - public async logout(@GetCurrentUserId() userId: string): Promise { - return this.authService.logout(userId); - } + // @ApiCreatedResponse({ + // description: 'User signed out successfully', + // type: Boolean, + // }) + // @HttpCode(HttpStatus.OK) + // @Post('logout') + // public async logout(@GetCurrentUserId() userId: string): Promise { + // return this.authService.logout(userId); + // } } diff --git a/backend/src/modules/auth-module/repositories/session.repository.ts b/backend/src/modules/auth-module/repositories/session.repository.ts index b329765..4c5ce30 100644 --- a/backend/src/modules/auth-module/repositories/session.repository.ts +++ b/backend/src/modules/auth-module/repositories/session.repository.ts @@ -35,6 +35,15 @@ export class SessionRepository { }); } + public findSessionByUserId(userId: string): Promise { + return this.sessionRepository + .createQueryBuilder('session') + .where('session.userCredentialsId = :userId', { + userId, + }) + .getMany(); + } + public attachSessionToResponse(response: Response, sessionId: string): void { response.cookie('session_id', sessionId, { httpOnly: true, diff --git a/backend/src/modules/auth-module/services/auth.service.ts b/backend/src/modules/auth-module/services/auth.service.ts index c27bb3a..7c1ad84 100644 --- a/backend/src/modules/auth-module/services/auth.service.ts +++ b/backend/src/modules/auth-module/services/auth.service.ts @@ -1,17 +1,10 @@ -import { ForbiddenException, Injectable } from '@nestjs/common'; -import { Response, Request } from 'express'; -import { Session } from 'src/entities'; +import { Injectable } from '@nestjs/common'; import { EncryptionService } from 'src/shared'; import { PasswordConfirmationMailService } from '../../sendgrid-module/services/password-confirmation.mail.service'; import { UserDataRepository } from '../../user-module/repositories/user-data.repository'; import { EmailVerificationService } from '../../verify-module/services/email-verification.service'; -import { - AccessTokenDto, - LoginResponseDto, - UserCredentialsDto, -} from '../models/dto'; -import { TokenPayload } from '../models/types'; +import { LoginResponseDto, UserCredentialsDto } from '../models/dto'; import { UserCredentialsRepository } from '../repositories/user-credentials.repository'; import { SessionService } from './session.service'; @@ -52,129 +45,129 @@ export class AuthService { token ); - return this.generateAndPersistTokens(user.id, user.email); + //return this.generateAndPersistTokens(user.id, user.email); } - public async signin( - userCredentials: UserCredentialsDto, - response: Response, - request: Request - ): Promise { - const user = await this.userCredentialsRepository.findUserByEmail( - userCredentials.email - ); + // public async signin( + // userCredentials: UserCredentialsDto, + // response: Response, + // request: Request + // ): Promise { + // const user = await this.userCredentialsRepository.findUserByEmail( + // userCredentials.email + // ); - if (!user) { - throw new ForbiddenException('Access Denied'); - } + // if (!user) { + // throw new ForbiddenException('Access Denied'); + // } - const passwordMatch = await EncryptionService.compareHash( - userCredentials.password, - user.hash - ); + // const passwordMatch = await EncryptionService.compareHash( + // userCredentials.password, + // user.hash + // ); - if (!passwordMatch) { - throw new ForbiddenException('Access Denied'); - } + // if (!passwordMatch) { + // throw new ForbiddenException('Access Denied'); + // } - await this.sessionService.checkSessionLimit(user.id); + // await this.sessionService.checkSessionLimit(user.id); - const sesseionId = await this.sessionService.createSession( - user.id, - request.headers['user-agent'] - ); + // const sesseionId = await this.sessionService.createSession( + // user.id, + // request.headers['user-agent'] + // ); - this.sessionService.attachSessionToResponse(response, sesseionId.sessionId); + // this.sessionService.attachSessionToResponse(response, sesseionId.sessionId); - return this.generateAndPersistTokens(user.id, user.email, true); - } + // return this.generateAndPersistTokens(user.id, user.email, true); + // } - public async logout(userId: string): Promise { - const affected = - await this.userCredentialsRepository.updateUserRefreshToken(userId, null); + // public async logout(userId: string): Promise { + // const affected = + // await this.userCredentialsRepository.updateUserRefreshToken(userId, null); - await this.sessionService.invalidateAllSessionsForUser(userId); + // await this.sessionService.invalidateAllSessionsForUser(userId); - return affected > 0; - } + // return affected > 0; + // } - public async refresh(request: Request): Promise { - const sessionId = request.cookies['session_id']; + // public async refresh(request: Request): Promise { + // const sessionId = request.cookies['session_id']; - if (!sessionId) { - throw new ForbiddenException('Session ID missing'); - } + // if (!sessionId) { + // throw new ForbiddenException('Session ID missing'); + // } - const session: Session = - await this.sessionService.findSessionBySessionId(sessionId); + // const session: Session = + // await this.sessionService.findSessionBySessionId(sessionId); - if (!session) { - throw new ForbiddenException('Invalid session'); - } + // if (!session) { + // throw new ForbiddenException('Invalid session'); + // } - const isUserAgentValid = await this.sessionService.validateSessionUserAgent( - sessionId, - request.headers['user-agent'] - ); + // const isUserAgentValid = await this.sessionService.validateSessionUserAgent( + // sessionId, + // request.headers['user-agent'] + // ); - if (!isUserAgentValid) { - throw new ForbiddenException('Invalid session - User agent mismatch'); - } + // if (!isUserAgentValid) { + // throw new ForbiddenException('Invalid session - User agent mismatch'); + // } - await this.sessionService.extendSessionExpiration(sessionId); + // await this.sessionService.extendSessionExpiration(sessionId); - const decodedToken: TokenPayload = await this.validateRefreshToken( - session.userCredentials['id'] - ); + // const decodedToken: TokenPayload = await this.validateRefreshToken( + // session.userCredentials['id'] + // ); - const newTokens = await this.generateAndPersistTokens( - decodedToken.sub, - decodedToken.email, - false - ); + // const newTokens = await this.generateAndPersistTokens( + // decodedToken.sub, + // decodedToken.email, + // false + // ); - return { access_token: newTokens.access_token }; - } + // return { access_token: newTokens.access_token }; + // } - private async generateAndPersistTokens( - userId: string, - email: string, - updateRefreshToken: boolean = false - ): Promise { - const tokens = await this.tokenManagementService.generateTokens( - userId, - email - ); + // private async generateAndPersistTokens( + // userId: string, + // email: string, + // updateRefreshToken: boolean = false + // ): Promise { + // const tokens = await this.tokenManagementService.generateTokens( + // userId, + // email + // ); - if (updateRefreshToken) { - await this.userCredentialsRepository.updateUserRefreshToken( - userId, - tokens.refresh_token - ); - } + // if (updateRefreshToken) { + // await this.userCredentialsRepository.updateUserRefreshToken( + // userId, + // tokens.refresh_token + // ); + // } - return { access_token: tokens.access_token, email: email, userId: userId }; - } + // return { access_token: tokens.access_token, email: email, userId: userId }; + // } - private async validateRefreshToken(userId: string): Promise { - const user = await this.userCredentialsRepository.findUserById(userId); + // private async validateRefreshToken(userId: string): Promise { + // const user = await this.userCredentialsRepository.findUserById(userId); - if (!user || !user.refreshToken) { - throw new Error('No refresh token found'); - } + // if (!user || !user.refreshToken) { + // throw new Error('No refresh token found'); + // } - const decodedToken = await this.tokenManagementService.verifyRefreshToken( - user.refreshToken - ); + // const decodedToken = await this.tokenManagementService.verifyRefreshToken( + // user.refreshToken + // ); - if (decodedToken.exp < Date.now() / 1000) { - throw new Error('Token expired'); - } + // if (decodedToken.exp < Date.now() / 1000) { + // throw new Error('Token expired'); + // } - if (decodedToken.sub !== user.id) { - throw new Error('Token subject mismatch'); - } + // if (decodedToken.sub !== user.id) { + // throw new Error('Token subject mismatch'); + // } - return decodedToken; - } + // return decodedToken; + // } } diff --git a/backend/src/modules/auth-module/services/session.service.ts b/backend/src/modules/auth-module/services/session.service.ts index 6dca4f2..efab889 100644 --- a/backend/src/modules/auth-module/services/session.service.ts +++ b/backend/src/modules/auth-module/services/session.service.ts @@ -43,6 +43,10 @@ export class SessionService { return this.sessionRepository.findSessionBySessionId(sessionId); } + public findSessionByUserId(userId: string): Promise { + return this.sessionRepository.findSessionByUserId(userId); + } + public attachSessionToResponse(response: Response, sessionId: string): void { this.sessionRepository.attachSessionToResponse(response, sessionId); } diff --git a/backend/src/modules/auth-module/strategies/access-token.strategie.ts b/backend/src/modules/auth-module/strategies/access-token.strategie.ts deleted file mode 100644 index 186383a..0000000 --- a/backend/src/modules/auth-module/strategies/access-token.strategie.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { PassportStrategy } from '@nestjs/passport'; -import { Strategy, ExtractJwt } from 'passport-jwt'; - -import { JwtPayload } from '../models/types'; - -@Injectable() -export class AccessTokenStrategy extends PassportStrategy( - Strategy, - 'jwt-access-token' -) { - public constructor(private readonly configService: ConfigService) { - super(AccessTokenStrategy.getJwtConfig(configService)); - } - - private static getJwtConfig(configService: ConfigService): any { - return { - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: configService.get('JWT_SECRET_AT'), - }; - } - - public async validate(payload: JwtPayload): Promise { - return payload; - } -} diff --git a/backend/src/modules/auth-module/strategies/index.ts b/backend/src/modules/auth-module/strategies/index.ts index c0e13f5..e69de29 100644 --- a/backend/src/modules/auth-module/strategies/index.ts +++ b/backend/src/modules/auth-module/strategies/index.ts @@ -1,2 +0,0 @@ -export * from './access-token.strategie'; -export * from './refresh-token.strategie'; diff --git a/backend/src/modules/auth-module/strategies/refresh-token.strategie.ts b/backend/src/modules/auth-module/strategies/refresh-token.strategie.ts deleted file mode 100644 index 4afeb7e..0000000 --- a/backend/src/modules/auth-module/strategies/refresh-token.strategie.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Injectable, ForbiddenException } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { PassportStrategy } from '@nestjs/passport'; -import { Request } from 'express'; -import { Strategy, ExtractJwt } from 'passport-jwt'; - -@Injectable() -export class RefreshTokenStrategy extends PassportStrategy( - Strategy, - 'jwt-refresh-token' -) { - public constructor(private readonly configService: ConfigService) { - super(RefreshTokenStrategy.createJwtStrategyOptions(configService)); - } - - private static createJwtStrategyOptions(configService: ConfigService): any { - return { - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: configService.get('JWT_SECRET_RT'), - passReqToCallback: true, - }; - } - - public async validate(req: Request, payload: any) { - const refresh_token: string = req - ?.get('authorization') - ?.replace('Bearer', '') - .trim(); - - if (!refresh_token) { - throw new ForbiddenException('Refresh token malformed'); - } - - return { - ...payload, - refresh_token, - }; - } -}