68 lines
2.9 KiB
TypeScript
68 lines
2.9 KiB
TypeScript
import { Inject, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
|
import { JwtService, JwtSignOptions } from '@nestjs/jwt';
|
|
import * as bcrypt from 'bcrypt';
|
|
import dayjs from 'dayjs';
|
|
import { isEmpty } from 'lodash';
|
|
import { AccountsEntity } from '../database/connections/ebitemp-api/entities';
|
|
import { TokenPayload } from './constants/token-payload.interface';
|
|
import { ACCESS_TOKEN_JWT_SERVICE } from './strategies/jwt/jwt-access-token.module';
|
|
import { REFRESH_TOKEN_JWT_SERVICE } from './strategies/jwt/jwt-refresh-token.module';
|
|
import { UsersAuthService } from './users/users-auth.service';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
private readonly logger = new Logger(AuthService.name);
|
|
|
|
constructor(
|
|
private readonly usersAuthService: UsersAuthService,
|
|
@Inject(ACCESS_TOKEN_JWT_SERVICE) private readonly accessTokenJwtService: JwtService,
|
|
@Inject(REFRESH_TOKEN_JWT_SERVICE) private readonly refreshTokenJwtService: JwtService
|
|
) {}
|
|
|
|
public async signJwts(account: AccountsEntity) {
|
|
const { token: accessToken, exp: accessTokenExp } = await this.getAccessToken(account);
|
|
const { token: refreshToken, exp: refreshTokenExp } = await this.getRefreshToken(account);
|
|
|
|
return {
|
|
accessToken: accessToken,
|
|
accessTokenExp: dayjs.unix(accessTokenExp).toJSON(),
|
|
refreshToken: refreshToken,
|
|
refreshTokenExp: dayjs.unix(refreshTokenExp).toJSON(),
|
|
};
|
|
}
|
|
|
|
public async getAccessToken(account: AccountsEntity, options?: JwtSignOptions) {
|
|
const payload: TokenPayload = { username: account.username, sub: account.id };
|
|
const token = await this.accessTokenJwtService.signAsync(payload, options);
|
|
const exp = this.accessTokenJwtService.decode(token).exp;
|
|
return { token, exp };
|
|
}
|
|
|
|
public async getRefreshToken(account: AccountsEntity, options?: JwtSignOptions) {
|
|
const payload: TokenPayload = { username: account.username, sub: account.id };
|
|
const token = await this.refreshTokenJwtService.signAsync(payload, options);
|
|
await this.usersAuthService.setCurrentRefreshTokenHash(account.id, token);
|
|
const exp = this.refreshTokenJwtService.decode(token).exp;
|
|
return { token, exp };
|
|
}
|
|
|
|
public async getAuthenticatedUser(username: string, password: string): Promise<AccountsEntity> {
|
|
try {
|
|
const account = await this.usersAuthService.getUserByUsername(username);
|
|
if (!account) throw new UnauthorizedException(`Username not found`);
|
|
await this.verifyPassword(password, account.password);
|
|
return account;
|
|
} catch (error) {
|
|
throw new UnauthorizedException(`Wrong credentials`);
|
|
}
|
|
}
|
|
|
|
private async verifyPassword(plainTextPassword: string, hashedPassword: string | null) {
|
|
const isPasswordMatching =
|
|
hashedPassword && !isEmpty(hashedPassword) ? await bcrypt.compare(plainTextPassword, hashedPassword) : null;
|
|
if (!isPasswordMatching) {
|
|
throw new UnauthorizedException(`Wrong password`);
|
|
}
|
|
}
|
|
}
|