fashionAvenue / server / src / auth / auth.service.ts
auth.service.ts
Raw
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;
  }
}