import {
CanActivate,
ExecutionContext,
HttpException,
HttpStatus,
Injectable,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@app/jwt';
import { Request } from 'express';
import { AuthService } from './auth.service';
import { I18nContext } from 'nestjs-i18n';
import { I18nTranslations } from '../.generate/i18n.generated';
import { TokenService } from './token.service';
import { TokenPayload } from './entity/token';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private readonly jwt: JwtService,
private readonly reflector: Reflector,
private readonly authService: AuthService,
private readonly tokenService: TokenService
) {}
async canActivate(ctx: ExecutionContext): Promise<boolean> {
const i18n = I18nContext.current<I18nTranslations>();
const isPublic = this.reflector.getAllAndOverride('isPublic', [
ctx.getHandler(),
ctx.getClass(),
]);
if (isPublic) {
return true;
}
const req = ctx.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(req);
if (!token) {
throw new HttpException(
i18n.t('exception.common.tokenError', {
lang: I18nContext.current().lang,
}),
HttpStatus.UNAUTHORIZED
);
}
try {
await this.jwt.verify(token);
const payload = this.jwt.decode<TokenPayload>(token);
req['user'] = payload;
if ('type' in payload && payload.type === 'api') {
const isValidApiToken = await this.authService.validateApiToken(
payload.email,
token
);
if (!isValidApiToken) {
throw new HttpException(
i18n.t('exception.common.tokenExpire', {
lang: I18nContext.current().lang,
}),
HttpStatus.UNAUTHORIZED
);
}
} else {
if (!await this.tokenService.accessTokenAlive(token)){
throw new HttpException(
i18n.t('exception.common.tokenExpire', {
lang: I18nContext.current().lang,
}),
HttpStatus.UNAUTHORIZED
);
}
}
return true;
} catch (err) {
throw new HttpException(
i18n.t('exception.common.tokenExpire', {
lang: I18nContext.current().lang,
}),
HttpStatus.UNAUTHORIZED
);
}
}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}