1+
2+ import { ConflictException , ForbiddenException , InternalServerErrorException } from "@nestjs/common" ;
3+ import { JwtService } from "@nestjs/jwt" ;
4+ import * as bcrypt from 'bcrypt' ;
5+ import { Tokens } from "../types" ;
6+ import { PrismaService } from '../../prisma/prisma.service' ;
7+ import { HashingException , UpdateHashException } from './../../exceptions' ;
8+
9+
10+ export abstract class AuthJwt {
11+ constructor ( protected readonly jwtService : JwtService , protected readonly prismaService : PrismaService ) { }
12+
13+ /**
14+ * This TypeScript function generates access and refresh tokens for a user based on their user ID and
15+ * email.
16+ * @param {number } userId - The `userId` parameter in the `getToken` function represents the unique
17+ * identifier of a user for whom the tokens are being generated. It is of type `number` and is used
18+ * to associate the tokens with a specific user in the system.
19+ * @param {string } email - The `email` parameter in the `getToken` function is a string that
20+ * represents the email address of a user. It is used as one of the payload properties when
21+ * generating the access token and refresh token for the user identified by the `userId`.
22+ * @returns The `getToken` function returns a Promise that resolves to an object containing two
23+ * properties: `access_token` and `refresh_token`. These tokens are generated using the `signAsync`
24+ * method from the `jwtService` with specific configurations such as `JWT_SECRET` for access token
25+ * and `RT` for refresh token. The access token expires in 10 minutes, while the refresh token
26+ * expires in 7
27+ */
28+ async getToken ( userId : number , email : string ) : Promise < Tokens > {
29+ try {
30+ const [ at , rt ] = await Promise . all ( [
31+ this . jwtService . signAsync (
32+ {
33+ sub : userId ,
34+ email
35+ } ,
36+ {
37+ secret : process . env . JWT_SECRET ,
38+ expiresIn : 60 * 10 ,
39+ }
40+ ) ,
41+ this . jwtService . signAsync (
42+ {
43+ sub : userId ,
44+ email
45+ } ,
46+ {
47+ secret : process . env . RT ,
48+ expiresIn : 60 * 60 * 24 * 7 ,
49+ } ,
50+ )
51+ ] )
52+
53+ return {
54+ access_token : at ,
55+ refresh_token : rt
56+ }
57+ } catch ( error ) {
58+ throw new ConflictException ( 'Something bad happened to get all token.' )
59+ }
60+ }
61+
62+ /**
63+ * The `updatedRtHash` function updates the refresh token hash for a user in a database using Prisma
64+ * ORM in TypeScript.
65+ * @param {number } userId - The `userId` parameter is a number that represents the unique identifier of
66+ * a user in the system.
67+ * @param {string } rt - The `rt` parameter in the `updatedRtHash` function is a string representing a
68+ * refresh token. It is used to generate a hash value that will be stored in the database for the
69+ * corresponding user identified by the `userId`.
70+ */
71+
72+ async updatedRtHash ( userId : number , rt : string ) : Promise < void > {
73+ try {
74+ const hash = await this . hash ( rt ) ;
75+
76+ await this . prismaService . user . update ( {
77+ where : { id : userId } ,
78+ data : {
79+ refreshTokenHash : hash ,
80+ } ,
81+ } ) ;
82+ } catch ( error ) {
83+ throw new UpdateHashException ( userId , error . message ) ;
84+ }
85+ }
86+
87+ /**
88+ * The function asynchronously hashes a given string using bcrypt with a specified salt or number of
89+ * rounds.
90+ * @param {string } data - The `data` parameter in the `hash` function is a string that represents the
91+ * data that you want to hash using the bcrypt algorithm. This data will be securely hashed using a
92+ * salt and the specified number of rounds before being returned as a hashed string.
93+ * @returns The `hash` function is returning a Promise that resolves to a string, which is the hashed
94+ * value of the input `data` string after using the bcrypt hashing algorithm with the specified salt
95+ * or rounds.
96+ */
97+ async hash ( data : string ) : Promise < string > {
98+ try {
99+ const saltOrRounds = 10 ;
100+ const hash = await bcrypt . hash ( data , saltOrRounds ) ;
101+ return hash ;
102+ } catch ( error ) {
103+ throw new HashingException ( error . message ) ;
104+ }
105+ }
106+
107+ /**
108+ * The `logout` function updates the `refreshTokenHash` field to null for a user with a specific ID.
109+ * @param {number } sub - The `sub` parameter in the `logout` function is a number that represents the
110+ * user's ID or subject identifier. It is used to identify the user whose refresh token hash needs to
111+ * be updated to `null` during the logout process.
112+ */
113+ async logout ( sub : number ) {
114+ try {
115+ await this . prismaService . user . update ( {
116+ where : { id : sub } ,
117+ data : {
118+ refreshTokenHash : null ,
119+ } ,
120+ } ) ;
121+ } catch ( error ) {
122+ throw new UpdateHashException ( sub , error . message ) ;
123+ }
124+ }
125+
126+
127+ /**
128+ * The function `refreshToken` in TypeScript checks and refreshes a user's token based on their ID
129+ * and refresh token hash stored in the database.
130+ * @param {number } sub - The `sub` parameter in the `refreshToken` function likely stands for
131+ * "subject" and is used to identify the user for whom the token is being refreshed. It is typically
132+ * a unique identifier for the user in the system, such as a user ID.
133+ * @param {string } token - The `token` parameter in the `refreshToken` function is a string that
134+ * represents the refresh token provided by the user for refreshing their authentication. This token
135+ * is used to verify the user's identity and generate new access tokens for continued access to the
136+ * application.
137+ * @returns The `refreshToken` function is returning a set of tokens after successfully refreshing
138+ * the user's refresh token. The tokens are generated using the `getToken` method and then a new
139+ * refresh token hash is generated and updated for the user. Finally, the function returns the newly
140+ * generated tokens.
141+ */
142+ async refreshToken ( sub : number , token : string ) {
143+ try {
144+
145+ const user = await this . prismaService . user . findFirst ( {
146+ where : {
147+ id : sub ,
148+ } ,
149+ } ) ;
150+
151+
152+ if ( ! user || ! user . refreshTokenHash ) {
153+ throw new ForbiddenException ( 'Authentication failed. Please check your credentials.' ) ;
154+ }
155+
156+ const rtMatches = await bcrypt . compare ( token , user . refreshTokenHash ) ;
157+ if ( ! rtMatches ) {
158+ throw new ForbiddenException ( 'El token ha expirado.' ) ;
159+ }
160+
161+ const tokens = await this . getToken ( user . id , user . email ) ;
162+
163+ const hashToken = await this . hash ( tokens . refresh_token ) ;
164+ await this . updatedRtHash ( user . id , hashToken ) ;
165+
166+ return tokens ;
167+ } catch ( error ) {
168+
169+ if ( error instanceof ForbiddenException ) {
170+ throw error ;
171+ }
172+ throw new InternalServerErrorException ( 'Error al procesar el token de actualización.' ) ;
173+ }
174+ }
175+ }
0 commit comments