import { Injectable, Inject } from '@nestjs/common'; import { RedisClientToken } from '../../core/configs/cache/redis-client.adapter.provider'; import { IRedisClient } from '../../core/configs/cache/IRedisClient'; import { JwtService } from '@nestjs/jwt'; import { JwtPayload } from '../models/jwt-payload.model'; @Injectable() export class TokenBlacklistService { constructor( @Inject(RedisClientToken) private readonly redis: IRedisClient, private readonly jwtService: JwtService, ) {} async addToBlacklist(token: string, expiresIn?: number): Promise { try { const decoded = this.jwtService.decode(token) as JwtPayload; if (!decoded) { throw new Error('Token inválido'); } const blacklistKey = this.buildBlacklistKey(token); const ttl = expiresIn || this.calculateTokenTTL(decoded); await this.redis.set(blacklistKey, 'blacklisted', ttl); } catch (error) { throw new Error(`Erro ao adicionar token à blacklist: ${error.message}`); } } async isBlacklisted(token: string): Promise { try { const blacklistKey = this.buildBlacklistKey(token); const result = await this.redis.get(blacklistKey); return result === 'blacklisted'; } catch (_error) { return false; } } async removeFromBlacklist(token: string): Promise { const blacklistKey = this.buildBlacklistKey(token); await this.redis.del(blacklistKey); } async clearUserBlacklist(userId: number): Promise { const pattern = `auth:blacklist:${userId}:*`; const keys = await this.redis.keys(pattern); if (keys.length > 0) { await this.redis.del(...keys); } } private buildBlacklistKey(token: string): string { const decoded = this.jwtService.decode(token) as JwtPayload; const tokenHash = this.hashToken(token); return `auth:blacklist:${decoded.id}:${tokenHash}`; } private calculateTokenTTL(payload: JwtPayload): number { const now = Math.floor(Date.now() / 1000); const exp = payload.exp || now + 8 * 60 * 60; return Math.max(0, exp - now); } private hashToken(token: string): string { const crypto = require('crypto'); return crypto .createHash('sha256') .update(token) .digest('hex') .substring(0, 16); } }