import { ForbiddenException , Injectable } from '@nestjs/common' ; import { ConfigService } from '@nestjs/config' ; import { JwtService } from '@nestjs/jwt' ; import { PrismaClientKnownRequestError } from '@prisma/client/runtime' ; import * as argon from 'argon2' ; import { PrismaService } from '../prisma/prisma.service' ; import { AuthDto } from './dto' ; import { JwtPayload , Tokens } from './types' ; @ Injectable ( ) export class AuthService { constructor ( private prisma , private jwtService , private config ) { } async signupLocal ( dto ) { const hash = await argon . hash ( dto . password ) ; const user = await this . prisma . user . create ( { data : { email : dto . email , hash , } , } ) . catch ( ( error ) => { if ( error instanceof PrismaClientKnownRequestError ) { if ( error . code === 'P2002' ) { throw new ForbiddenException ( 'Credentials incorrect' ) ; } } throw error ; } ) ; const tokens = await this . getTokens ( user . id , user . email ) ; await this . updateRtHash ( user . id , tokens . refresh_token ) ; return tokens ; } async signinLocal ( dto ) { const user = await this . prisma . user . findUnique ( { where : { email : dto . email , } , } ) ; if ( ! user ) throw new ForbiddenException ( 'Access Denied' ) ; const passwordMatches = await argon . verify ( user . hash , dto . password ) ; if ( ! passwordMatches ) throw new ForbiddenException ( 'Access Denied' ) ; const tokens = await this . getTokens ( user . id , user . email ) ; await this . updateRtHash ( user . id , tokens . refresh_token ) ; return tokens ; } async logout ( userId ) { await this . prisma . user . updateMany ( { where : { id : userId , hashedRt : { not : null , } , } , data : { hashedRt : null , } , } ) ; return true ; } async refreshTokens ( userId , rt ) { const user = await this . prisma . user . findUnique ( { where : { id : userId , } , } ) ; if ( ! user || ! user . hashedRt ) throw new ForbiddenException ( 'Access Denied' ) ; const rtMatches = await argon . verify ( user . hashedRt , rt ) ; if ( ! rtMatches ) throw new ForbiddenException ( 'Access Denied' ) ; const tokens = await this . getTokens ( user . id , user . email ) ; await this . updateRtHash ( user . id , tokens . refresh_token ) ; return tokens ; } async updateRtHash ( userId , rt ) { const hash = await argon . hash ( rt ) ; await this . prisma . user . update ( { where : { id : userId , } , data : { hashedRt : hash , } , } ) ; } async getTokens ( userId , email ) { const jwtPayload = { sub : userId , email : email , } ; const [ at , rt ] = await Promise . all ( [ this . jwtService . signAsync ( jwtPayload , { secret : this . config . get < string > ( 'AT_SECRET' ) , expiresIn : 60 * 15 , } ) , this . jwtService . signAsync ( jwtPayload , { secret : this . config . get < string > ( 'RT_SECRET' ) , expiresIn : 60 * 60 * 24 * 7 , } ) , ] ) ; return { access_token : at , refresh_token : rt , } ; } }