From 87a7eb0931f1b1d374ace297daffe3580831e094 Mon Sep 17 00:00:00 2001 From: renolation Date: Tue, 13 May 2025 02:20:31 +0700 Subject: [PATCH] fix auth --- src/app.module.ts | 7 +- src/authentication/authentication.module.ts | 47 ++-- src/authentication/authentication.service.ts | 213 ++++++++++--------- 3 files changed, 137 insertions(+), 130 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index e5d227d..cbbc5d2 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -4,6 +4,8 @@ import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; import * as Joi from 'joi'; +import {UsersModule} from "./users/user.module"; +import {AuthenticationModule} from "./authentication/authentication.module"; @Module({ imports: [ @@ -17,6 +19,7 @@ import * as Joi from 'joi'; username: configService.get('POSTGRES_USER'), password: configService.get('POSTGRES_PASSWORD'), database: configService.get('POSTGRES_DB'), + autoLoadEntities: true, ssl: { rejectUnauthorized: false, // Needed for Neon and similar managed DBs }, @@ -28,7 +31,9 @@ import * as Joi from 'joi'; JWT_SECRET: Joi.string().required(), JWT_EXPIRATION_TIME: Joi.string().required(), }) - }) + }), + UsersModule, + AuthenticationModule ], controllers: [AppController], providers: [AppService], diff --git a/src/authentication/authentication.module.ts b/src/authentication/authentication.module.ts index 0e13d04..52bd964 100644 --- a/src/authentication/authentication.module.ts +++ b/src/authentication/authentication.module.ts @@ -1,30 +1,31 @@ -import { Module } from '@nestjs/common'; -import { AuthenticationService } from './authentication.service'; -import { AuthenticationController } from './authentication.controller'; -import { PassportModule } from '@nestjs/passport'; -import { LocalStrategy } from './local.strategy'; -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { JwtModule } from '@nestjs/jwt'; +import {Module} from '@nestjs/common'; +import {AuthenticationService} from './authentication.service'; +import {AuthenticationController} from './authentication.controller'; +import {PassportModule} from '@nestjs/passport'; +import {LocalStrategy} from './local.strategy'; +import {ConfigModule, ConfigService} from '@nestjs/config'; +import {JwtModule} from '@nestjs/jwt'; import {JwtStrategy} from "./jwt.strategy"; import {UsersModule} from "../users/user.module"; @Module({ - imports: [UsersModule, PassportModule, + imports: [UsersModule, PassportModule, - ConfigModule, - JwtModule.registerAsync({ - imports: [ConfigModule], - inject: [ConfigService], - useFactory: (configService: ConfigService) => ({ - secret: configService.get('JWT_SECRET'), - signOptions: { - expiresIn: `${configService.get('JWT_EXPIRATION_TIME')}s`, - }, - }), - }), + ConfigModule, + JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (configService: ConfigService) => ({ + secret: configService.get('JWT_SECRET'), + signOptions: { + expiresIn: `${configService.get('JWT_EXPIRATION_TIME')}s`, + }, + }), + }), - ] as const, - providers: [AuthenticationService, LocalStrategy, JwtStrategy] as const, - controllers: [AuthenticationController] as const, + ] as const, + providers: [AuthenticationService, LocalStrategy, JwtStrategy] as const, + controllers: [AuthenticationController] as const, }) -export class AuthenticationModule {} \ No newline at end of file +export class AuthenticationModule { +} \ No newline at end of file diff --git a/src/authentication/authentication.service.ts b/src/authentication/authentication.service.ts index f16a5f5..4cbaf3b 100644 --- a/src/authentication/authentication.service.ts +++ b/src/authentication/authentication.service.ts @@ -1,121 +1,122 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import {HttpException, HttpStatus, Injectable} from '@nestjs/common'; import RegisterDto from './dto/register.dto'; import * as bcrypt from 'bcrypt'; -import { JwtService } from '@nestjs/jwt'; -import { ConfigService } from '@nestjs/config'; +import {JwtService} from '@nestjs/jwt'; +import {ConfigService} from '@nestjs/config'; import {UsersService} from "../users/user.service"; import PostgresErrorCode from 'src/database/postgresErrorCodes.enum'; @Injectable() export class AuthenticationService { - constructor( - private readonly usersService: UsersService, - private readonly jwtService: JwtService, - private readonly configService: ConfigService, - ) {} + constructor( + private readonly usersService: UsersService, + private readonly jwtService: JwtService, + private readonly configService: ConfigService, + ) { + } - public async register(registrationData: RegisterDto) { - const hashedPassword = await bcrypt.hash(registrationData.password, 10); - try { - const createdUser = await this.usersService.create({ - ...registrationData, - password: hashedPassword, - }); - createdUser.password = undefined; - return createdUser; - } catch (error) { - if (error?.code === PostgresErrorCode.UniqueViolation) { - throw new HttpException( - 'User with that email already exists', - HttpStatus.BAD_REQUEST, + public async register(registrationData: RegisterDto) { + const hashedPassword = await bcrypt.hash(registrationData.password, 10); + try { + const createdUser = await this.usersService.create({ + ...registrationData, + password: hashedPassword, + }); + createdUser.password = undefined; + return createdUser; + } catch (error) { + if (error?.code === PostgresErrorCode.UniqueViolation) { + throw new HttpException( + 'User with that email already exists', + HttpStatus.BAD_REQUEST, + ); + } + console.log(error); + throw new HttpException( + 'Something went wrong', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + public getCookieWithJwtAccessToken( + userId: number, + isSecondFactorAuthenticated = false, + ) { + const payload: TokenPayload = {userId, isSecondFactorAuthenticated}; + const token = this.jwtService.sign(payload, { + secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'), + expiresIn: `${this.configService.get( + 'JWT_ACCESS_TOKEN_EXPIRATION_TIME', + )}s`, + }); + return `Authentication=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get( + 'JWT_ACCESS_TOKEN_EXPIRATION_TIME', + )}`; + } + + public getCookieWithJwtRefreshToken(userId: number) { + const payload: TokenPayload = {userId}; + const token = this.jwtService.sign(payload, { + secret: this.configService.get('JWT_REFRESH_TOKEN_SECRET'), + expiresIn: this.configService.get('JWT_ACCESS_TOKEN_EXPIRATION_TIME'), + + }); + const cookie = `Refresh=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get( + 'JWT_REFRESH_TOKEN_EXPIRATION_TIME', + )}`; + return { + cookie, + token, + }; + } + + public getCookiesForLogOut() { + return [ + 'Authentication=; HttpOnly; Path=/; Max-Age=0', + 'Refresh=; HttpOnly; Path=/; Max-Age=0', + ]; + } + + public async getAuthenticatedUser(email: string, plainTextPassword: string) { + try { + const user = await this.usersService.getByEmail(email); + await this.verifyPassword(plainTextPassword, user.password); + return user; + } catch (error) { + throw new HttpException( + 'Wrong credentials provided', + HttpStatus.BAD_REQUEST, + ); + } + } + + private async verifyPassword( + plainTextPassword: string, + hashedPassword: string, + ) { + const isPasswordMatching = await bcrypt.compare( + plainTextPassword, + hashedPassword, ); - } - throw new HttpException( - 'Something went wrong', - HttpStatus.INTERNAL_SERVER_ERROR, - ); + if (!isPasswordMatching) { + throw new HttpException( + 'Wrong credentials provided', + HttpStatus.BAD_REQUEST, + ); + } } - } - public getCookieWithJwtAccessToken( - userId: number, - isSecondFactorAuthenticated = false, - ) { - const payload: TokenPayload = { userId, isSecondFactorAuthenticated }; - const token = this.jwtService.sign(payload, { - secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'), - expiresIn: `${this.configService.get( - 'JWT_ACCESS_TOKEN_EXPIRATION_TIME', - )}s`, - }); - return `Authentication=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get( - 'JWT_ACCESS_TOKEN_EXPIRATION_TIME', - )}`; - } - - public getCookieWithJwtRefreshToken(userId: number) { - const payload: TokenPayload = { userId }; - const token = this.jwtService.sign(payload, { - secret: this.configService.get('JWT_REFRESH_TOKEN_SECRET'), - expiresIn: `${this.configService.get( - 'JWT_REFRESH_TOKEN_EXPIRATION_TIME', - )}s`, - }); - const cookie = `Refresh=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get( - 'JWT_REFRESH_TOKEN_EXPIRATION_TIME', - )}`; - return { - cookie, - token, - }; - } - - public getCookiesForLogOut() { - return [ - 'Authentication=; HttpOnly; Path=/; Max-Age=0', - 'Refresh=; HttpOnly; Path=/; Max-Age=0', - ]; - } - - public async getAuthenticatedUser(email: string, plainTextPassword: string) { - try { - const user = await this.usersService.getByEmail(email); - await this.verifyPassword(plainTextPassword, user.password); - return user; - } catch (error) { - throw new HttpException( - 'Wrong credentials provided', - HttpStatus.BAD_REQUEST, - ); + public async getUserFromAuthenticationToken(token: string) { + const payload: TokenPayload = this.jwtService.verify(token, { + secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'), + }); + if (payload.userId) { + return this.usersService.getById(payload.userId); + } } - } - private async verifyPassword( - plainTextPassword: string, - hashedPassword: string, - ) { - const isPasswordMatching = await bcrypt.compare( - plainTextPassword, - hashedPassword, - ); - if (!isPasswordMatching) { - throw new HttpException( - 'Wrong credentials provided', - HttpStatus.BAD_REQUEST, - ); + public getCookieForLogOut() { + return `Authentication=; HttpOnly; Path=/; Max-Age=0`; } - } - - public async getUserFromAuthenticationToken(token: string) { - const payload: TokenPayload = this.jwtService.verify(token, { - secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'), - }); - if (payload.userId) { - return this.usersService.getById(payload.userId); - } - } - - public getCookieForLogOut() { - return `Authentication=; HttpOnly; Path=/; Max-Age=0`; - } } \ No newline at end of file