From 1aa237f255f3946383e7e6bae516b58a958e8e50 Mon Sep 17 00:00:00 2001 From: isra el Date: Fri, 21 Apr 2023 09:45:52 +0300 Subject: [PATCH] chore(api): update auth guards --- api/src/auth/auth.controller.ts | 6 +-- api/src/auth/auth.service.ts | 6 ++- api/src/auth/{ => guards}/auth.guard.ts | 4 +- .../auth/guards/can-modify-api-key.guard.ts | 38 +++++++++++++++++++ api/src/gateway/gateway.controller.ts | 2 +- 5 files changed, 49 insertions(+), 7 deletions(-) rename api/src/auth/{ => guards}/auth.guard.ts (93%) create mode 100644 api/src/auth/guards/can-modify-api-key.guard.ts diff --git a/api/src/auth/auth.controller.ts b/api/src/auth/auth.controller.ts index 15c8fdc..0f21a41 100644 --- a/api/src/auth/auth.controller.ts +++ b/api/src/auth/auth.controller.ts @@ -12,8 +12,9 @@ import { } from '@nestjs/common' import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger' import { LoginInputDTO, RegisterInputDTO } from './auth.dto' -import { AuthGuard } from './auth.guard' +import { AuthGuard } from './guards/auth.guard' import { AuthService } from './auth.service' +import { CanModifyApiKey } from './guards/can-modify-api-key.guard' @ApiTags('auth') @Controller('auth') @@ -69,8 +70,7 @@ export class AuthController { return { data } } - // TODO: Add a guard to check if the user is the owner of the api key - @UseGuards(AuthGuard) + @UseGuards(AuthGuard, CanModifyApiKey) @ApiOperation({ summary: 'Generate Api Key' }) @ApiBearerAuth() @HttpCode(HttpStatus.OK) diff --git a/api/src/auth/auth.service.ts b/api/src/auth/auth.service.ts index 31857ba..8bf4dc2 100644 --- a/api/src/auth/auth.service.ts +++ b/api/src/auth/auth.service.ts @@ -115,10 +115,14 @@ export class AuthService { return this.apiKeyModel.find({ user: currentUser._id }) } - async findApiKeys(params) { + async findApiKey(params) { return this.apiKeyModel.findOne(params) } + async findApiKeyById(apiKeyId: string) { + return this.apiKeyModel.findById(apiKeyId) + } + async deleteApiKey(apiKeyId: string) { const apiKey = await this.apiKeyModel.findOne({ _id: apiKeyId }) if (!apiKey) { diff --git a/api/src/auth/auth.guard.ts b/api/src/auth/guards/auth.guard.ts similarity index 93% rename from api/src/auth/auth.guard.ts rename to api/src/auth/guards/auth.guard.ts index ec33b8b..bc8f5ed 100644 --- a/api/src/auth/auth.guard.ts +++ b/api/src/auth/guards/auth.guard.ts @@ -7,7 +7,7 @@ import { } from '@nestjs/common' import { JwtService } from '@nestjs/jwt' import { UsersService } from 'src/users/users.service' -import { AuthService } from './auth.service' +import { AuthService } from '../auth.service' import * as bcrypt from 'bcryptjs' @Injectable() @@ -34,7 +34,7 @@ export class AuthGuard implements CanActivate { const apiKeyStr = request.query.apiKey if (apiKeyStr) { var regex = new RegExp(`^${apiKeyStr.substr(0, 17)}`, 'g') - const apiKey = await this.authService.findApiKeys({ + const apiKey = await this.authService.findApiKey({ apiKey: { $regex: regex }, }) diff --git a/api/src/auth/guards/can-modify-api-key.guard.ts b/api/src/auth/guards/can-modify-api-key.guard.ts new file mode 100644 index 0000000..a6be522 --- /dev/null +++ b/api/src/auth/guards/can-modify-api-key.guard.ts @@ -0,0 +1,38 @@ +import { + CanActivate, + ExecutionContext, + HttpException, + HttpStatus, + Injectable, +} from '@nestjs/common' +import mongoose from 'mongoose' +import { UserRole } from 'src/users/user-roles.enum' +import { AuthService } from '../auth.service' + +@Injectable() +export class CanModifyApiKey implements CanActivate { + constructor(private authService: AuthService) {} + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest() + + const apiKeyId = request.params.id + const userId = request.user?.id + + const isValidId = mongoose.Types.ObjectId.isValid(apiKeyId) + if (!isValidId) { + throw new HttpException({ error: 'Invalid id' }, HttpStatus.BAD_REQUEST) + } + + const apiKey = await this.authService.findApiKeyById(apiKeyId) + if ( + !!userId && + (apiKey?.user == userId.toString() || + request.user?.role == UserRole.ADMIN) + ) { + return true + } + + throw new HttpException({ error: 'Unauthorized' }, HttpStatus.UNAUTHORIZED) + } +} diff --git a/api/src/gateway/gateway.controller.ts b/api/src/gateway/gateway.controller.ts index ad90db4..75288c4 100644 --- a/api/src/gateway/gateway.controller.ts +++ b/api/src/gateway/gateway.controller.ts @@ -9,7 +9,7 @@ import { Get, } from '@nestjs/common' import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger' -import { AuthGuard } from 'src/auth/auth.guard' +import { AuthGuard } from 'src/auth/guards/auth.guard' import { RegisterDeviceInputDTO, SendSMSInputDTO } from './gateway.dto' import { GatewayService } from './gateway.service' import { CanModifyDevice } from './guards/can-modify-device.guard'