apps/api: add AuthParams decorator & isTokenExpired function

This commit is contained in:
vchikalkin 2024-05-14 14:01:59 +03:00
parent cc9ab04112
commit 092d2c98a1
3 changed files with 53 additions and 16 deletions

View File

@ -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();
}
}

View File

@ -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<Params>((_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;
});

View File

@ -0,0 +1,3 @@
export function isTokenExpired(error: Error) {
return error.name?.toLocaleLowerCase().includes('expired');
}