From cd301a795d8e8d78ee6f312e86bd79fe2f22e377 Mon Sep 17 00:00:00 2001 From: luizy Date: Sun, 26 Nov 2023 23:25:03 +0900 Subject: [PATCH] feat: Guards add - SessionGuard add - CommandGuard add [#125] --- packages/backend/src/command.guard.ts | 10 ++++++++ .../backend/src/quizzes/quizzes.controller.ts | 25 ++++++++----------- .../backend/src/session/session.decorator.ts | 8 ++++++ packages/backend/src/session/session.guard.ts | 16 ++++++++++++ 4 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 packages/backend/src/command.guard.ts create mode 100644 packages/backend/src/session/session.decorator.ts create mode 100644 packages/backend/src/session/session.guard.ts diff --git a/packages/backend/src/command.guard.ts b/packages/backend/src/command.guard.ts new file mode 100644 index 0000000..97f86be --- /dev/null +++ b/packages/backend/src/command.guard.ts @@ -0,0 +1,10 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; + +@Injectable() +export class CommandGuard implements CanActivate { + canActivate(context: ExecutionContext): boolean { + const request = context.switchToHttp().getRequest(); + const command = request.body['command']; + return typeof command === 'string' && command.startsWith('git'); + } +} diff --git a/packages/backend/src/quizzes/quizzes.controller.ts b/packages/backend/src/quizzes/quizzes.controller.ts index 08aa6a9..783f757 100644 --- a/packages/backend/src/quizzes/quizzes.controller.ts +++ b/packages/backend/src/quizzes/quizzes.controller.ts @@ -7,9 +7,9 @@ import { HttpException, HttpStatus, Res, - Req, Inject, Delete, + UseGuards, } from '@nestjs/common'; import { ApiTags, @@ -25,8 +25,11 @@ import { QuizzesDto } from './dto/quizzes.dto'; import { CommandRequestDto } from './dto/command-request.dto'; import { CommandResponseDto } from './dto/command-response.dto'; import { SessionService } from '../session/session.service'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import { ContainersService } from '../containers/containers.service'; +import { SessionId } from '../session/session.decorator'; +import { SessionGuard } from '../session/session.guard'; +import { CommandGuard } from '../command.guard'; @ApiTags('quizzes') @Controller('api/v1/quizzes') @@ -66,6 +69,7 @@ export class QuizzesController { } @Post(':id/command') + @UseGuards(CommandGuard) @ApiOperation({ summary: 'Git 명령을 실행합니다.' }) @ApiResponse({ status: 200, @@ -78,22 +82,20 @@ export class QuizzesController { @Param('id') id: number, @Body() execCommandDto: CommandRequestDto, @Res() response: Response, - @Req() request: Request, + @SessionId() sessionId: string, ): Promise { try { - let sessionId = request.cookies?.sessionId; - if (!sessionId) { // 세션 아이디가 없다면 + this.logger.log('info', 'no session id. creating session..'); response.cookie( 'sessionId', (sessionId = await this.sessionService.createSession()), { httpOnly: true, - // 개발 이후 활성화 시켜야함 - // secure: true, }, ); // 세션 아이디를 생성한다. + this.logger.log('info', `session id: ${sessionId} created`); } let containerId = await this.sessionService.getContainerIdBySessionId( @@ -148,6 +150,7 @@ export class QuizzesController { } @Delete(':id/command') + @UseGuards(SessionGuard) @ApiOperation({ summary: 'Git 명령기록과, 할당된 컨테이너를 삭제합니다' }) @ApiResponse({ status: 200, @@ -157,15 +160,9 @@ export class QuizzesController { @ApiParam({ name: 'id', description: '문제 ID' }) async deleteCommandHistory( @Param('id') id: number, - @Req() request: Request, + @SessionId() sessionId: string, ): Promise { try { - const sessionId = request.cookies?.sessionId; - - if (!sessionId) { - return; - } - const containerId = await this.sessionService.getContainerIdBySessionId( sessionId, id, diff --git a/packages/backend/src/session/session.decorator.ts b/packages/backend/src/session/session.decorator.ts new file mode 100644 index 0000000..f23d275 --- /dev/null +++ b/packages/backend/src/session/session.decorator.ts @@ -0,0 +1,8 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; + +export const SessionId = createParamDecorator( + (data: unknown, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + return request.cookies['sessionId']; + }, +); diff --git a/packages/backend/src/session/session.guard.ts b/packages/backend/src/session/session.guard.ts new file mode 100644 index 0000000..1cd47e8 --- /dev/null +++ b/packages/backend/src/session/session.guard.ts @@ -0,0 +1,16 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; + +/** + * @description session guard + * @returns {boolean} + * check if sessionId exists + * @dependency cookie-parser + */ +@Injectable() +export class SessionGuard implements CanActivate { + canActivate(context: ExecutionContext): boolean { + const request = context.switchToHttp().getRequest(); + // cookie-parser must be used before this guard + return request['cookies'].sessionId; + } +}