1- import {
2- BadRequestException ,
3- ConflictException ,
4- Inject ,
5- Injectable ,
6- UnauthorizedException ,
7- } from '@nestjs/common' ;
1+ import { HttpStatus , Inject , Injectable } from '@nestjs/common' ;
82import { InjectRedis } from '@nestjs-modules/ioredis' ;
93import Redis from 'ioredis' ;
104import { SignInDto , SignUpDto , VerifyDto } from '../dtos' ;
@@ -18,6 +12,7 @@ import { InjectQueue } from '@nestjs/bullmq';
1812import { Queues , RegisterCodeEvent } from '@shared/workers' ;
1913import type { Queue } from 'bullmq' ;
2014import { MailJobs } from '@shared/workers/enum' ;
15+ import { BaseException } from '@shared/error' ;
2116
2217@Injectable ( )
2318export class AuthService {
@@ -39,20 +34,27 @@ export class AuthService {
3934 const cachedData = await this . redis . get ( redisKey ) ;
4035
4136 if ( cachedData ) {
42- throw new BadRequestException ( {
43- code : 'REGISTRATION_IN_PROGRESS' ,
44- message : 'Код уже был отправлен. Проверьте почту или подождите 15 минут.' ,
45- } ) ;
37+ throw new BaseException (
38+ {
39+ code : 'REGISTRATION_IN_PROGRESS' ,
40+ message : 'Код уже был отправлен. Проверьте почту или подождите 15 минут.' ,
41+ details : [ { target : 'email' , message : 'Verification code already sent' } ] ,
42+ } ,
43+ HttpStatus . BAD_REQUEST ,
44+ ) ;
4645 }
4746
4847 const isExists = await this . findUserCommand . execute ( { email : dto . email } ) ;
4948
5049 if ( isExists ) {
51- throw new ConflictException ( {
52- code : 'USER_ALREADY_EXISTS' ,
53- message : 'Email уже занят другим аккаунтом' ,
54- details : { email : dto . email } ,
55- } ) ;
50+ throw new BaseException (
51+ {
52+ code : 'USER_ALREADY_EXISTS' ,
53+ message : 'Email уже занят другим аккаунтом' ,
54+ details : [ { target : 'email' , value : dto . email } ] ,
55+ } ,
56+ HttpStatus . CONFLICT ,
57+ ) ;
5658 }
5759
5860 const hashPass = await argon . hash ( dto . password ) ;
@@ -95,10 +97,13 @@ export class AuthService {
9597 const cachedData = await this . redis . get ( redisKey ) ;
9698
9799 if ( ! cachedData ) {
98- throw new BadRequestException ( {
99- code : 'REGISTRATION_EXPIRED' ,
100- message : 'Срок регистрации истек или email не найден. Попробуйте снова.' ,
101- } ) ;
100+ throw new BaseException (
101+ {
102+ code : 'REGISTRATION_EXPIRED' ,
103+ message : 'Срок регистрации истек или email не найден. Попробуйте снова.' ,
104+ } ,
105+ HttpStatus . GONE ,
106+ ) ;
102107 }
103108
104109 const userData = JSON . parse ( cachedData ) ;
@@ -114,10 +119,14 @@ export class AuthService {
114119 } ) ;
115120
116121 if ( ! verifyResult . valid ) {
117- throw new BadRequestException ( {
118- code : 'INVALID_OTP' ,
119- message : 'Неверный или истекший код подтверждения' ,
120- } ) ;
122+ throw new BaseException (
123+ {
124+ code : 'INVALID_OTP' ,
125+ message : 'Неверный или истекший код подтверждения' ,
126+ details : [ { target : 'code' , message : 'OTP code is invalid or expired' } ] ,
127+ } ,
128+ HttpStatus . BAD_REQUEST ,
129+ ) ;
121130 }
122131
123132 const user = await this . createUserCommand . execute ( {
@@ -145,19 +154,25 @@ export class AuthService {
145154 const { user, security } = await this . findUserCommand . execute ( { email : dto . email } ) ;
146155
147156 if ( ! user || ! security ) {
148- throw new UnauthorizedException ( {
149- code : 'INVALID_CREDENTIALS' ,
150- message : 'Неверный email или пароль' ,
151- } ) ;
157+ throw new BaseException (
158+ {
159+ code : 'INVALID_CREDENTIALS' ,
160+ message : 'Неверный email или пароль' ,
161+ } ,
162+ HttpStatus . UNAUTHORIZED ,
163+ ) ;
152164 }
153165
154166 const isPasswordValid = await argon . verify ( security . passwordHash , dto . password ) ;
155167
156168 if ( ! isPasswordValid ) {
157- throw new UnauthorizedException ( {
158- code : 'INVALID_CREDENTIALS' ,
159- message : 'Неверный email или пароль' ,
160- } ) ;
169+ throw new BaseException (
170+ {
171+ code : 'INVALID_CREDENTIALS' ,
172+ message : 'Неверный email или пароль' ,
173+ } ,
174+ HttpStatus . UNAUTHORIZED ,
175+ ) ;
161176 }
162177
163178 const { id } = await this . sessionRepo . create ( {
@@ -181,30 +196,39 @@ export class AuthService {
181196 public refresh = async ( token : string , metadata : DeviceMetadata ) => {
182197 const payload = await this . tokenService . validateToken ( token , 'refresh' ) ;
183198
184- if ( ! payload || ! payload . jti ) {
185- throw new UnauthorizedException ( {
186- code : 'INVALID_TOKEN' ,
187- message : 'Сессия недействительна или истекла' ,
188- } ) ;
199+ if ( ! payload ?. jti ) {
200+ throw new BaseException (
201+ {
202+ code : 'INVALID_TOKEN' ,
203+ message : 'Сессия недействительна или истекла' ,
204+ } ,
205+ HttpStatus . UNAUTHORIZED ,
206+ ) ;
189207 }
190208
191209 const session = await this . sessionRepo . findById ( payload . jti ) ;
192210
193211 if ( ! session || session . isRevoked ) {
194- throw new UnauthorizedException ( {
195- code : 'SESSION_REVOKED' ,
196- message : 'Ваша сессия была отозвана или завершена' ,
197- } ) ;
212+ throw new BaseException (
213+ {
214+ code : 'SESSION_REVOKED' ,
215+ message : 'Ваша сессия была отозвана или завершена' ,
216+ } ,
217+ HttpStatus . UNAUTHORIZED ,
218+ ) ;
198219 }
199220
200221 const { user } = await this . findUserCommand . execute ( { id : session . userId } ) ;
201222
202223 if ( ! user ) {
203224 await this . sessionRepo . revoke ( session . id ) ;
204- throw new UnauthorizedException ( {
205- code : 'USER_NOT_FOUND' ,
206- message : 'Аккаунт пользователя не найден' ,
207- } ) ;
225+ throw new BaseException (
226+ {
227+ code : 'USER_NOT_FOUND' ,
228+ message : 'Аккаунт пользователя не найден' ,
229+ } ,
230+ HttpStatus . UNAUTHORIZED ,
231+ ) ;
208232 }
209233
210234 await this . sessionRepo . revoke ( session . id ) ;
@@ -228,20 +252,32 @@ export class AuthService {
228252 const payload = await this . tokenService . validateToken ( token , 'refresh' ) ;
229253
230254 if ( ! payload ?. jti ) {
231- throw new UnauthorizedException ( { code : 'SESSION_EXPIRED' , message : 'Сессия истекла' } ) ;
255+ throw new BaseException (
256+ {
257+ code : 'SESSION_EXPIRED' ,
258+ message : 'Сессия уже истекла' ,
259+ } ,
260+ HttpStatus . UNAUTHORIZED ,
261+ ) ;
232262 }
233263
234264 const session = await this . sessionRepo . findById ( payload . jti ) ;
235265
236- if ( ! session ) {
237- throw new UnauthorizedException ( {
238- code : 'SESSION_NOT_FOUND' ,
239- message : 'Сессия не найдена' ,
240- } ) ;
266+ if ( session ) {
267+ const isRevoked = await this . sessionRepo . revoke ( session . id ) ;
268+
269+ if ( ! isRevoked ) {
270+ throw new BaseException (
271+ {
272+ code : 'SIGNOUT_FAILED' ,
273+ message : 'Не удалось завершить сессию на сервере. Попробуйте позже.' ,
274+ details : [ { target : 'database' , message : 'Session revocation failed' } ] ,
275+ } ,
276+ HttpStatus . SERVICE_UNAVAILABLE ,
277+ ) ;
278+ }
241279 }
242280
243- await this . sessionRepo . revoke ( session . id ) ;
244-
245281 return { success : true , message : 'Успешно вышли из системы!' } ;
246282 } ;
247283}
0 commit comments