From 2f01adeade88fddefeae9c3b39c1230a0119c77b Mon Sep 17 00:00:00 2001 From: SauravDhakal Date: Sun, 12 Apr 2026 08:06:05 +0545 Subject: [PATCH] fix: Prisma issue fix + Auth done --- src/app.module.ts | 21 ++++++++++++++++++++- src/auth/auth.controller.ts | 13 ++++++++++--- src/auth/auth.module.ts | 13 +++++++++++-- src/auth/auth.service.ts | 25 +++++++++---------------- src/auth/guards/auth.guard.ts | 7 ++++++- src/prisma/prisma.service.ts | 7 ++++++- src/user/user.service.ts | 12 +++++------- 7 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index dd546a9..b476645 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,7 +5,7 @@ import { UserModule } from './user/user.module'; import { AuthModule } from './auth/auth.module'; import { RequestContextMiddleware } from 'core/als/request-context.middleware'; import { RequestContextModule } from 'core/als/request-context.module'; -import { ConfigModule } from '@nestjs/config'; +import { ConfigModule, ConfigService } from '@nestjs/config'; import { PrismaModule } from './prisma/prisma.module'; import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core'; import { ResponseInterceptor } from 'common/interceptors/response.interceptor'; @@ -72,7 +72,26 @@ import { ExpressAdapter } from '@bull-board/express'; ], }) export class AppModule implements NestModule { + constructor(private readonly configService: ConfigService) { }; + configure(consumer: MiddlewareConsumer) { consumer.apply(RequestContextMiddleware).forRoutes('*paths'); } + + // Make sure all required env vars are present + onModuleInit() { + const requiredEnvVars = [ + "TOKEN_SECRET", + "DATABASE_URL", + "BULL_MQ_REDIS_HOST", + "BULL_MQ_REDIS_PORT" + ] + + const missingEnvVars = requiredEnvVars.filter((envVar) => !(this.configService.get(envVar))) + + if (missingEnvVars.length > 0) { + Logger.error(`One or more env variables are missing. Add: ${missingEnvVars.join(', ')} to env file.`) + process.exit(1) + } + } } diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 19c702e..8b1fa82 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -76,10 +76,17 @@ export class AuthController { @IsTempToken() @UseGuards(AuthGuard) @Post('/complete-profile') - async completeUserProfile(@Body() body: CompleteProfileSetupRequestDTO): Promise { - await this.authService.completeProfileSetup(body); + async completeUserProfile(@Body() body: CompleteProfileSetupRequestDTO) { + const { accessToken, refreshToken, user } = await this.authService.completeProfileSetup(body); - return 'Welcome'; + return { + message: "Welcome to our app", + data: { + accessToken, + refreshToken, + user + } + } } logout() { } diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 33cc37b..126e3f9 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -4,10 +4,11 @@ import { AuthController } from './auth.controller'; import { APP_GUARD } from '@nestjs/core'; import { AuthGuard } from './guards/auth.guard'; import { UserModule } from 'src/user/user.module'; -import { JwtModule } from '@nestjs/jwt'; import { RequestContextModule } from 'core/als/request-context.module'; import { BullModule } from '@nestjs/bullmq'; import { PrismaModule } from 'src/prisma/prisma.module'; +import { JwtModule } from '@nestjs/jwt'; +import { ConfigModule, ConfigService } from '@nestjs/config'; @Global() @Module({ @@ -23,8 +24,16 @@ import { PrismaModule } from 'src/prisma/prisma.module'; BullModule.registerQueue({ name: "mail" }), + JwtModule.registerAsync({ + global: true, + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (config: ConfigService) => ({ + secret: config.get("TOKEN_SECRET"), + signOptions: { expiresIn: '7d' } + }) + }), UserModule, - JwtModule, RequestContextModule, PrismaModule ], diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index b1b7ff8..b2adbae 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -83,7 +83,7 @@ export class AuthService { const now = Number(new Date()) / 1000; if (!otpExists) - throw new BadRequestException("No user found") + throw new BadRequestException("No OTP request found") else if (otpExists.otp !== dto.otp) throw new BadRequestException("Invalid OTP") else if ((Number(otpExists.expiresAt) / 1000 < now)) { @@ -217,43 +217,36 @@ export class AuthService { resetPassword() { } - // TODO: Use nest jwt + // TODO: If remember me is there, sign for like 30d maybe private async genSignedTokens(token: TokenInputType) { - const accessToken = await this.jwtService.signAsync(token, { - secret: 'demo', - }); + const accessToken = await this.jwtService.signAsync(token); const refreshToken = await this.jwtService.signAsync( { userId: token.userId, }, - { - secret: 'demo', - }, ); return { accessToken, refreshToken }; } private async genSignedTempToken(token: OTPTokenInputType) { - const accessToken = await this.jwtService.signAsync(token, { - secret: 'demo', - }); + const accessToken = await this.jwtService.signAsync(token); const refreshToken = await this.jwtService.signAsync( { userId: token.userId, }, - { - secret: 'demo', - }, ); return { accessToken, refreshToken }; } - private genOtp() { - return 123456; + genOtp(): number { + const array = new Uint32Array(1); + crypto.getRandomValues(array); + const otp = array[0] % 900000 + 100000; + return otp; } } diff --git a/src/auth/guards/auth.guard.ts b/src/auth/guards/auth.guard.ts index 4ea5e4a..6a89f89 100644 --- a/src/auth/guards/auth.guard.ts +++ b/src/auth/guards/auth.guard.ts @@ -13,6 +13,7 @@ import { Reflector } from '@nestjs/core'; import { PUBLIC_KEY, TEMP_TOKEN_KEY } from 'common/keys'; import { UserService } from 'src/user/user.service'; import { USER_ACCOUNT_STATUS } from 'prisma/generated/prisma/enums'; +import { ConfigService } from '@nestjs/config'; @Injectable() export class AuthGuard implements CanActivate { @@ -21,6 +22,7 @@ export class AuthGuard implements CanActivate { private readonly jwtService: JwtService, private readonly requestContext: RequestContextService, private readonly userService: UserService, + private readonly configService: ConfigService, ) { } async canActivate(context: ExecutionContext) { @@ -42,9 +44,12 @@ export class AuthGuard implements CanActivate { try { const payload: JwtPayload = await this.jwtService.verifyAsync(token, { - secret: 'demo', + secret: this.configService.get("TOKEN_SECRET"), }); + if (isTempToken && payload.status !== USER_ACCOUNT_STATUS.pending) + throw new UnauthorizedException() + // TODO: Redis + Org too, blacklist token const userExists = await this.userService.findById(payload.userId); diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts index 12972e9..ba4e716 100644 --- a/src/prisma/prisma.service.ts +++ b/src/prisma/prisma.service.ts @@ -16,6 +16,9 @@ import { TransactionClient } from 'prisma/generated/prisma/internal/prismaNamesp export class PrismaService extends PrismaClient implements OnModuleDestroy, OnModuleInit { + + private readonly db: PrismaClient; + constructor( private readonly ctx: RequestContextService, private readonly configService: ConfigService, @@ -31,6 +34,8 @@ export class PrismaService adapter: adapter, log: ['info', 'warn'], }); + + this.db = new PrismaClient({ adapter, log: ['warn', 'info', 'error'] }) } async onModuleInit() { try { @@ -51,6 +56,6 @@ export class PrismaService * Else returns itself. * */ get client(): TransactionClient { - return this.ctx.tx ?? this; + return this.ctx.tx ?? this.db; } } diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 927137a..5f1ba66 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -56,14 +56,14 @@ export class UserService { } async findUserForAuth(email: string) { - return await this.prisma.user.findUnique({ + return await this.prisma.client.user.findUnique({ where: { email }, omit: { password: false }, // Password is omitted by default, we are just reverting it }); } async findById(id: string) { - return await this.prisma.user.findUnique({ + return await this.prisma.client.user.findUnique({ where: { id: id, }, @@ -71,8 +71,7 @@ export class UserService { } async findByEmail(email: string) { - const client = this.prisma.client.user ?? this.prisma.user; - return await client.findUnique({ + return await this.prisma.client.user.findUnique({ where: { email: email, }, @@ -80,7 +79,7 @@ export class UserService { } async updateRefreshToken(id: string, refreshToken: string) { - return await this.prisma.user.update({ + return await this.prisma.client.user.update({ where: { id }, data: { refreshToken }, }); @@ -90,8 +89,7 @@ export class UserService { * USER OTP SERVICES * */ async findByEmailInOTP(email: string) { - const client = this.prisma.client.userOTP ?? this.prisma.userOTP; - return await client.findUnique({ + return await this.prisma.client.userOTP.findUnique({ where: { email, },