From eff2103c3eb74393ae91a59e68416fe9166d320c Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Thu, 6 Jun 2024 16:24:53 +0300 Subject: [PATCH] apps/api: add /refresh-token methods remove refresh-token logic from app controller --- apps/api/src/account/account.controller.ts | 19 +++++ apps/api/src/app.controller.ts | 93 +++++----------------- apps/api/src/ldap/ldap.controller.ts | 29 +++++-- 3 files changed, 61 insertions(+), 80 deletions(-) diff --git a/apps/api/src/account/account.controller.ts b/apps/api/src/account/account.controller.ts index 5d295c9..02bbcaa 100644 --- a/apps/api/src/account/account.controller.ts +++ b/apps/api/src/account/account.controller.ts @@ -23,6 +23,7 @@ import { ApiResponse, ApiTags } from '@nestjs/swagger'; import { FastifyReply, FastifyRequest } from 'fastify'; import { cookieOptions } from 'src/config/cookie'; import { env } from 'src/config/env'; +import { AuthParams, Params } from 'src/decorators/auth-mode.decorator'; import { AuthToken } from 'src/decorators/token.decorator'; import { Credentials } from 'src/dto/credentials'; import { Account } from 'src/schemas/account.schema'; @@ -128,6 +129,24 @@ export class AccountController implements BaseAuthController { return reply.status(302).redirect('/login'); } + @Get('/refresh-token') + @ApiResponse({ + status: HttpStatus.OK, + }) + async refreshToken( + @AuthToken() token: string, + @AuthParams() { refreshToken }: Params, + @Res() reply: FastifyReply + ) { + if (!refreshToken) return reply.status(HttpStatus.UNAUTHORIZED).send(); + + const newToken = await this.accountService.refreshToken(token); + + reply.header('Authorization', `Bearer ${newToken}`); + + return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, cookieOptions).send(); + } + @Get('/get-user') async getUser( @Req() req: FastifyRequest, diff --git a/apps/api/src/app.controller.ts b/apps/api/src/app.controller.ts index 1051424..5511eb8 100644 --- a/apps/api/src/app.controller.ts +++ b/apps/api/src/app.controller.ts @@ -1,96 +1,39 @@ -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 { Controller, Get, HttpStatus, Req, Res, UnauthorizedException } from '@nestjs/common'; import { ApiExcludeController } from '@nestjs/swagger'; import { FastifyReply, FastifyRequest } from 'fastify'; -import { cookieOptions } from 'src/config/cookie'; @Controller() @ApiExcludeController() export class AppController { - constructor( - private readonly appService: AppService, - private readonly accountService: AccountService, - private readonly ldapService: LdapService - ) {} + constructor(private readonly appService: AppService) {} @Get('auth') public async auth( @Req() req: FastifyRequest, @Res() reply: FastifyReply, @AuthToken() token: string, - @AuthParams() authParams: Params + @AuthParams() { authMode }: Params ) { try { - return this.handleDefaultCheck(authParams, req, reply, token); + const { aud } = this.appService.checkToken(token); + const originalUri = req.headers['x-original-uri']; + + if ( + authMode === 'ldap-tfa' && + aud === 'auth' && + !['/auth', '/login', '/socket.io'].some((x) => originalUri.includes(x)) + ) { + return reply.status(HttpStatus.UNAUTHORIZED).send(); + } + + reply.header('Authorization', `Bearer ${token}`); + + return reply.send(); } catch (error) { - if (isTokenExpired(error)) { - return this.handleExpiredToken(authParams, token, req, reply); - } - - return this.handleError(req, reply); + throw new UnauthorizedException(error); } } - - private async handleExpiredToken( - { authMode, refreshToken }: Params, - token: string, - req: FastifyRequest, - reply: FastifyReply - ) { - if (!refreshToken) return this.handleError(req, reply); - - try { - let newToken = ''; - - if (authMode === 'ldap-tfa') { - newToken = await this.ldapService.refreshToken(token); - } - - if (authMode === 'ldap') { - newToken = await this.ldapService.refreshToken(token); - } - - if (authMode === 'account') { - newToken = await this.accountService.refreshToken(token); - } - - reply.header('Authorization', `Bearer ${newToken}`); - - return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, cookieOptions).send(); - } catch { - return this.handleError(req, reply); - } - } - - private handleDefaultCheck( - { authMode }: Params, - req: FastifyRequest, - reply: FastifyReply, - token: string - ) { - const { aud } = this.appService.checkToken(token); - const originalUri = req.headers['x-original-uri']; - - if ( - authMode === 'ldap-tfa' && - aud === 'auth' && - !['/auth', '/login', '/socket.io'].some((x) => originalUri.includes(x)) - ) { - return this.handleError(req, reply); - } - - 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/ldap/ldap.controller.ts b/apps/api/src/ldap/ldap.controller.ts index 31ed2f5..e5b2279 100644 --- a/apps/api/src/ldap/ldap.controller.ts +++ b/apps/api/src/ldap/ldap.controller.ts @@ -19,6 +19,7 @@ import { ApiResponse, ApiTags } from '@nestjs/swagger'; import { FastifyReply, FastifyRequest } from 'fastify'; import { cookieOptions } from 'src/config/cookie'; import { env } from 'src/config/env'; +import { AuthParams, Params } from 'src/decorators/auth-mode.decorator'; import { AuthToken } from 'src/decorators/token.decorator'; import type { BaseAuthController } from 'src/types/auth-controller'; import { User } from 'src/utils/ldap'; @@ -27,7 +28,7 @@ import { User } from 'src/utils/ldap'; @ApiTags('ldap') export class LdapController implements BaseAuthController { cookieOptions: CookieSerializeOptions; - constructor(protected readonly ldapTfaService: LdapService) {} + constructor(protected readonly ldapService: LdapService) {} private clearCookies(req, reply) { if (req.cookies) { @@ -49,7 +50,7 @@ export class LdapController implements BaseAuthController { @Res() reply: FastifyReply ) { try { - const token = await this.ldapTfaService.login(credentials); + const token = await this.ldapService.login(credentials); return reply.setCookie(env.COOKIE_TOKEN_NAME, token, cookieOptions).status(200).send(); } catch { @@ -59,24 +60,42 @@ export class LdapController implements BaseAuthController { @Get('/logout') async logout(@Req() req: FastifyRequest, @Res() reply: FastifyReply, @AuthToken() token: string) { - if (token) await this.ldapTfaService.logout(token); + if (token) await this.ldapService.logout(token); this.clearCookies(req, reply); return reply.status(302).redirect('/login'); } + @Get('/refresh-token') + @ApiResponse({ + status: HttpStatus.OK, + }) + async refreshToken( + @AuthToken() token: string, + @AuthParams() { refreshToken }: Params, + @Res() reply: FastifyReply + ) { + if (!refreshToken) return reply.status(HttpStatus.UNAUTHORIZED).send(); + + const newToken = await this.ldapService.refreshToken(token); + + reply.header('Authorization', `Bearer ${newToken}`); + + return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, cookieOptions).send(); + } + @Get('/get-user') @ApiResponse({ status: HttpStatus.OK, type: User, }) async getUser( - @Req() req: FastifyRequest, + @Req() _req: FastifyRequest, @Res() reply: FastifyReply, @AuthToken() token: string ) { - const user = await this.ldapTfaService.getUser(token); + const user = await this.ldapService.getUser(token); if (!user) throw new UnauthorizedException('User not found');