import { ForbiddenException, Injectable, Logger } from '@nestjs/common'; import { UserService } from '../user/user.service'; import { JwtService } from '@nestjs/jwt'; import { AuthDto } from './dto/auth.dto'; import * as bcrypt from 'bcrypt'; import { Tokens } from './types'; import { UserDto } from './dto/user.dto'; @Injectable() export class AuthService { private readonly logger: Logger = new Logger('auth resolver'); constructor( private userService: UserService, private jwtService: JwtService, ) {} hashData(data: string) { return bcrypt.hash(data, 10); } async getTokens(userId: number, username: string) { const [at, rt] = await Promise.all([ this.jwtService.signAsync( { sub: userId, username, }, { secret: 'AT-SECRET', expiresIn: 60 * 60, }, ), this.jwtService.signAsync( { sub: userId, username, }, { secret: 'RT-SECRET', expiresIn: 60 * 60 * 24 * 7, }, ), ]); return { access_token: at, refresh_token: rt, }; } async register(dto: UserDto): Promise<Tokens> { try { const { password, ...userInfo } = dto; const hash = await this.hashData(password); const newUser = await this.userService.create({ hash, ...userInfo }); const tokens = await this.getTokens(newUser.id, newUser.username); await this.updateRtHash(newUser.id, tokens.refresh_token); return tokens; } catch (err) { this.logger.error(err); } } async updateRtHash(userId: number, rt: string) { const hash = await this.hashData(rt); await this.userService.updateRtHash(userId, hash); } async login(dto: AuthDto) { this.logger.log(dto); try { const user = await this.userService.findByUsername(dto.username); if (!user) throw new ForbiddenException('Access Denied'); const passwordMatches = await bcrypt.compare(dto.password, user.hash); if (!passwordMatches) throw new ForbiddenException('Access Denied'); const tokens = await this.getTokens(user.id, user.username); await this.updateRtHash(user.id, tokens.refresh_token); return tokens; } catch (err) { this.logger.error(err); throw new ForbiddenException('Access Denied'); } } async logout(userId: number) { await this.userService.logout(userId); } async refreshTokens(userId: number, rt: string) { const user = await this.userService.findById(userId); if (!user || !user.hashedRt) throw new ForbiddenException('Access Denied'); const rtMatches = await bcrypt.compare(rt, user.hashedRt); if (!rtMatches) throw new ForbiddenException('Access Denied'); const tokens = await this.getTokens(user.id, user.username); await this.updateRtHash(user.id, tokens.refresh_token); return tokens; } }