import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; import { UsersService } from '../users/users.service'; import { getJwtSecret } from './auth.constants'; import { RedisService } from '../redis/redis.service'; import type { Request } from 'express'; export interface JwtPayload { sub: string; email?: string; role?: string; phoneNumber?: string; } @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor( private readonly usersService: UsersService, private readonly redisService: RedisService, ) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: getJwtSecret(), passReqToCallback: true, }); } async validate(req: Request, payload: JwtPayload) { const rawToken = ExtractJwt.fromAuthHeaderAsBearerToken()(req); if (rawToken) { const isBlacklisted = await this.redisService.get(`bl_token:${rawToken}`); if (isBlacklisted) { throw new UnauthorizedException('این توکن باطل شده است. لطفاً مجدداً وارد شوید'); } } // Handle fallback admin ID only in non-production environments if ADMIN_EMAIL matches if (payload.sub === '12345678-1234-1234-1234-123456789012') { if (process.env.NODE_ENV === 'production') { throw new UnauthorizedException('حساب کاربری مدیریت معتبر نیست'); } const adminEmail = process.env.ADMIN_EMAIL; if (adminEmail && payload.email === adminEmail) { return { id: payload.sub, email: adminEmail, role: 'Admin', }; } throw new UnauthorizedException('حساب کاربری مدیریت معتبر نیست'); } const user = await this.usersService.findById(payload.sub); if (!user) { throw new UnauthorizedException('کاربر یافت نشد'); } return user; } }