From a157553b78fe4b39a0791b1bede60272f5b04c63 Mon Sep 17 00:00:00 2001 From: Mathis Date: Fri, 12 Jul 2024 14:08:09 +0200 Subject: [PATCH] feat(auth): add UserGuard and AdminGuard This commit introduces UserGuard and AdminGuard, two new authorization guards. These guards verify the access permissions of users and admin respectively, by checking the provided token in the authorization header. Unauthorized users will receive UnauthorizedException. --- src/auth/auth.guard.ts | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/auth/auth.guard.ts diff --git a/src/auth/auth.guard.ts b/src/auth/auth.guard.ts new file mode 100644 index 0000000..20201f9 --- /dev/null +++ b/src/auth/auth.guard.ts @@ -0,0 +1,81 @@ +import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'; +import { Request } from 'express'; +import { CredentialsService } from "src/credentials/credentials.service"; +import { DrizzleService } from "src/drizzle/drizzle.service"; +import { UsersTable } from "src/schema"; +import { eq } from "drizzle-orm"; + +@Injectable() +export class UserGuard implements CanActivate { + constructor( + private readonly credentialService: CredentialsService, + private readonly databaseService: DrizzleService + ) {} + + async canActivate( + context: ExecutionContext, + ): Promise { + const request: Request = context.switchToHttp().getRequest(); + const authHeader = request.headers.authorization; + + if (!authHeader) + throw new UnauthorizedException('No authorization header found.'); + + const token = authHeader.split(' ')[1]; + const vToken = await this.credentialService.verifyAuthToken(token) + + const user = await this.databaseService.use() + .select() + .from(UsersTable) + .where(eq(UsersTable.uuid, vToken.payload.sub)) + + if (user.length !== 1) + throw new UnauthorizedException('No such user found.'); + + if (user[0].emailCode) + throw new UnauthorizedException('Email not verified.'); + + // Inject user ID into request body + request.body.sourceUserId = vToken.payload.sub; + + return true; + } +} + +@Injectable() +export class AdminGuard implements CanActivate { + constructor( + private readonly credentialService: CredentialsService, + private readonly databaseService: DrizzleService + ) {} + + async canActivate( + context: ExecutionContext, + ): Promise { + const request: Request = context.switchToHttp().getRequest(); + const authHeader = request.headers.authorization; + + if (!authHeader) + throw new UnauthorizedException('No authorization header found.'); + + const token = authHeader.split(' ')[1]; + const vToken = await this.credentialService.verifyAuthToken(token) + + const user = await this.databaseService.use() + .select() + .from(UsersTable) + .where(eq(UsersTable.uuid, vToken.payload.sub)) + + if (user.length !== 1) + throw new UnauthorizedException('No such user found.'); + + if (!user[0].isAdmin) { + throw new UnauthorizedException('Administrator only..'); + } + + // Inject user ID into request body + request.body.sourceUserId = vToken.payload.sub; + + return true; + } +} \ No newline at end of file