import { Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bcrypt from 'bcryptjs'; import { UserService } from '../user/service/user.service'; import { User } from '../user/domain/user'; import { RoleService } from '../role/service/role.service'; @Injectable() export class AuthService { constructor( private readonly userService: UserService, private readonly jwtService: JwtService, private readonly roleService: RoleService, ) {} async register(data: Omit): Promise { const userRole = await this.roleService.findByName('Usuário Comum'); if (!userRole) { throw new Error('Default role "Usuário Comum" not found'); } return this.userService.create({ ...data, role: userRole, isActive: true, }); } async login(email: string, pass: string): Promise<{ accessToken: string; refreshToken: string; user: Omit }> { const user = await this.userService.findByEmail(email); if (!user) { throw new UnauthorizedException('Invalid credentials'); } const isMatch = await bcrypt.compare(pass, user.password); if (!isMatch) { throw new UnauthorizedException('Invalid credentials'); } if (!user.isActive) { throw new UnauthorizedException('User is inactive'); } return this.generateTokensForUser(user); } async refresh(email: string, refreshToken: string): Promise<{ accessToken: string; refreshToken: string; user: Omit }> { try { const payload = await this.jwtService.verifyAsync(refreshToken); if (payload.email !== email) { throw new UnauthorizedException('Invalid refresh token'); } const user = await this.userService.findByEmail(email); if (!user || !user.currentRefreshToken || !user.isActive) { throw new UnauthorizedException('Session expired or user inactive'); } const isMatch = await bcrypt.compare(refreshToken, user.currentRefreshToken); if (!isMatch) { throw new UnauthorizedException('Invalid session'); } return this.generateTokensForUser(user); } catch (e) { throw new UnauthorizedException('Invalid or expired refresh token'); } } async logout(userId: number): Promise { await this.userService.update(userId, { currentRefreshToken: undefined } as any); } private async generateTokensForUser(user: User) { const payload = { sub: user.id, email: user.email, role: user.role?.name, tenantId: user.tenantId, permissions: user.role?.permissions || [] }; const accessToken = await this.jwtService.signAsync(payload, { expiresIn: '15m' }); const refreshToken = await this.jwtService.signAsync({ email: user.email }, { expiresIn: '7d' }); const salt = await bcrypt.genSalt(10); const hashedRefreshToken = await bcrypt.hash(refreshToken, salt); await this.userService.update(user.id, { currentRefreshToken: hashedRefreshToken } as any); const { password, currentRefreshToken, ...result } = user; return { accessToken, refreshToken, user: result, }; } async validateUserById(id: number): Promise | null> { const user = await this.userService.findById(id); if (!user) return null; const { password, currentRefreshToken, ...result } = user; return result; } }