From 092d2c98a136b1aba12e27b189197042fcbc5af1 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Tue, 14 May 2024 14:01:59 +0300 Subject: [PATCH] apps/api: add AuthParams decorator & isTokenExpired function --- apps/api/src/app.controller.ts | 43 ++++++++++++------- .../api/src/decorators/auth-mode.decorator.ts | 23 ++++++++++ apps/api/src/utils/error.ts | 3 ++ 3 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 apps/api/src/decorators/auth-mode.decorator.ts create mode 100644 apps/api/src/utils/error.ts diff --git a/apps/api/src/app.controller.ts b/apps/api/src/app.controller.ts index e4bf59c..ac6e6ee 100644 --- a/apps/api/src/app.controller.ts +++ b/apps/api/src/app.controller.ts @@ -1,8 +1,10 @@ import { AccountService } from './account/account.service'; import { AppService } from './app.service'; import { env } from './config/env'; +import { AuthParams, Params } from './decorators/auth-mode.decorator'; import { AuthToken } from './decorators/token.decorator'; import { LdapService } from './ldap/ldap.service'; +import { isTokenExpired } from './utils/error'; import { Controller, Get, HttpStatus, Req, Res } from '@nestjs/common'; import { ApiExcludeController } from '@nestjs/swagger'; import { FastifyReply, FastifyRequest } from 'fastify'; @@ -21,31 +23,33 @@ export class AppController { public async auth( @Req() req: FastifyRequest, @Res() reply: FastifyReply, - @AuthToken() token: string + @AuthToken() token: string, + @AuthParams() authParams: Params ) { + const { refreshToken } = authParams; + try { return this.handleDefaultCheck(req, reply, token); } catch (error) { - const _err = error as Error; - const isTokenExpired = _err.name?.toLocaleLowerCase().includes('expired'); - const refreshToken = req.headers['refresh-token'] === '1'; - - if (isTokenExpired && refreshToken) return this.handleExpiredToken(req, reply, token); + if (isTokenExpired(error) && refreshToken) { + try { + return this.handleExpiredToken(authParams, token, req, reply); + } catch { + return this.handleError(req, reply); + } + } return this.handleError(req, reply); } } - private handleDefaultCheck(req: FastifyRequest, reply: FastifyReply, token: string) { - this.appService.checkToken(token); - reply.header('Authorization', `Bearer ${token}`); - - return reply.send(); - } - - private async handleExpiredToken(req: FastifyRequest, reply: FastifyReply, token: string) { + private async handleExpiredToken( + { authMode }: Params, + token: string, + req: FastifyRequest, + reply: FastifyReply + ) { try { - const authMode = req.headers['auth-mode']; const newToken = authMode === 'account' ? await this.accountService.refreshToken(token) @@ -58,7 +62,14 @@ export class AppController { } } - private handleError(req: FastifyRequest, reply: FastifyReply) { + private handleDefaultCheck(_req: FastifyRequest, reply: FastifyReply, token: string) { + this.appService.checkToken(token); + reply.header('Authorization', `Bearer ${token}`); + + return reply.send(); + } + + private handleError(_req: FastifyRequest, reply: FastifyReply) { return reply.status(HttpStatus.UNAUTHORIZED).send(); } } diff --git a/apps/api/src/decorators/auth-mode.decorator.ts b/apps/api/src/decorators/auth-mode.decorator.ts new file mode 100644 index 0000000..205c17d --- /dev/null +++ b/apps/api/src/decorators/auth-mode.decorator.ts @@ -0,0 +1,23 @@ +import type { ExecutionContext } from '@nestjs/common'; +import { createParamDecorator, UnauthorizedException } from '@nestjs/common'; + +export type AuthMode = 'ldap' | 'ldap-tfa' | 'account' | undefined; +export type RefreshToken = '1' | undefined; +export type Params = { + authMode: AuthMode; + refreshToken: boolean; +}; + +export const AuthParams = createParamDecorator((_data: unknown, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + + const authMode = request.headers['auth-mode'] as AuthMode; + const refreshToken = (request.headers['refresh-token'] as RefreshToken) === '1'; + + if (!authMode) throw new UnauthorizedException('Auth mode is missing'); + + return { + authMode, + refreshToken, + } as Params; +}); diff --git a/apps/api/src/utils/error.ts b/apps/api/src/utils/error.ts new file mode 100644 index 0000000..61c4522 --- /dev/null +++ b/apps/api/src/utils/error.ts @@ -0,0 +1,3 @@ +export function isTokenExpired(error: Error) { + return error.name?.toLocaleLowerCase().includes('expired'); +}