From 9578b37c648e9c8f1e61ba3ce35088604426fffa Mon Sep 17 00:00:00 2001 From: geonhee-min Date: Wed, 10 Dec 2025 17:13:28 +0900 Subject: [PATCH] =?UTF-8?q?issue=20#=20-=20=EB=94=94=EB=A0=89=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- drizzle.config.ts | 2 +- drizzle/schema.ts | 25 +++++++------- src/app.module.ts | 3 +- .../dto/base-response.dto.ts | 0 src/common/filters/all-exceptions.filter.ts | 34 +++++++++++++++++++ src/main.ts | 4 +-- src/middleware/auth/auth.service.ts | 2 +- .../auth/guard/access-token.guard.ts | 27 ++++++--------- .../auth/strategy/access-token.strategy.ts | 13 ++++--- src/modules/account/account.repo.ts | 4 +-- .../check-duplication-response.dto.ts | 2 +- .../account/dto/login/login-response.dto.ts | 2 +- .../refresh-access-token-response.dto.ts | 2 +- .../reset-password-response.dto.ts | 2 +- ...nd-email-verification-code-response.dto.ts | 2 +- .../send-reset-password-code-response.dto.ts | 2 +- .../account/dto/signup/signup-response.dto.ts | 2 +- ...fy-email-verification-code-response.dto.ts | 2 +- ...verify-reset-password-code-response.dto.ts | 2 +- 19 files changed, 84 insertions(+), 48 deletions(-) rename src/{modules/account => common}/dto/base-response.dto.ts (100%) diff --git a/drizzle.config.ts b/drizzle.config.ts index 17f841c..3dfa20e 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'drizzle-kit'; import dotenv from 'dotenv'; -dotenv.config(); +dotenv.config({ path: `.env.${process.env.NODE_ENV}` }); export default defineConfig({ dialect: "postgresql", diff --git a/drizzle/schema.ts b/drizzle/schema.ts index f37ef9e..5621f15 100644 --- a/drizzle/schema.ts +++ b/drizzle/schema.ts @@ -20,7 +20,7 @@ export const userBlockingIdSeq = pgSequence("user_blocking_id_seq", { startWith export const emailAddressIdSeq = pgSequence("email_address_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false }) export const comment = pgTable("comment", { - id: uuid().primaryKey().notNull(), + id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(), content: text(), createdAt: date("created_at"), isDeleted: boolean("is_deleted").default(false), @@ -72,19 +72,20 @@ export const participant = pgTable("participant", { ]); export const schedule = pgTable("schedule", { - id: uuid().primaryKey().notNull(), - name: varchar(), - startDate: date("start_date"), - endDate: date("end_date"), - status: varchar(), + id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(), + name: varchar().notNull(), + startDate: date("start_date").notNull(), + endDate: date("end_date").notNull(), + status: varchar().default('yet').notNull(), content: text(), - isDeleted: boolean("is_deleted").default(false), - type: varchar(), + isDeleted: boolean("is_deleted").default(false).notNull(), + type: varchar().notNull(), createdAt: date("created_at"), - owner: uuid(), - style: varchar(), - startTime: time("start_time"), - endTime: time("end_time"), + owner: uuid().notNull(), + style: varchar().notNull(), + startTime: time("start_time").notNull(), + endTime: time("end_time").notNull(), + dayList: varchar("day_list"), }, (table) => [ index("schedule_enddatetime_idx").using("btree", table.endDate.asc().nullsLast().op("date_ops")), index("schedule_name_idx").using("btree", table.name.asc().nullsLast().op("text_ops"), table.content.asc().nullsLast().op("text_ops")), diff --git a/src/app.module.ts b/src/app.module.ts index 79a53e9..6d37aed 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,9 +6,10 @@ import { RedisModule } from './redis/redis.module'; import { AccountModule } from './modules/account/account.module'; import { MailerModule } from './util/mailer/mailer.module'; import { AppConfigModule } from './config/config.module'; +import { ScheduleModule } from './modules/schedule/schedule.module'; @Module({ - imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule], + imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule, ScheduleModule], controllers: [AppController], providers: [AppService], }) diff --git a/src/modules/account/dto/base-response.dto.ts b/src/common/dto/base-response.dto.ts similarity index 100% rename from src/modules/account/dto/base-response.dto.ts rename to src/common/dto/base-response.dto.ts diff --git a/src/common/filters/all-exceptions.filter.ts b/src/common/filters/all-exceptions.filter.ts index 8397661..6fd06e8 100644 --- a/src/common/filters/all-exceptions.filter.ts +++ b/src/common/filters/all-exceptions.filter.ts @@ -5,6 +5,7 @@ import { HttpException, HttpStatus } from '@nestjs/common'; +import { JsonWebTokenError, TokenExpiredError } from '@nestjs/jwt'; import { FastifyReply, FastifyRequest } from 'fastify'; @Catch() @@ -13,6 +14,39 @@ export class AllExceptionsFilter implements ExceptionFilter { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const request = ctx.getRequest(); + console.log(exception); + + // TokenExpiredError + if (exception instanceof TokenExpiredError) { + const status = HttpStatus.UNAUTHORIZED; + + const responseBody = { + statusCode: status, + message: 'Access Token Expired', + code: 'AccessTokenExpired', + timestamp: new Date().toISOString(), + path: ctx.getRequest().url + }; + + response.status(status).send(responseBody); + return; + } + + // JsonWebTokenError + if (exception instanceof JsonWebTokenError) { + const status = HttpStatus.UNAUTHORIZED; + + const responseBody = { + statusCode: status, + message: 'Invalid Token', + code: 'InvalidToken', + timestamp: new Date().toISOString(), + path: ctx.getRequest().url + }; + + response.status(status).send(responseBody); + return; + } let status = exception instanceof HttpException diff --git a/src/main.ts b/src/main.ts index 9f4de66..b1cc409 100644 --- a/src/main.ts +++ b/src/main.ts @@ -45,7 +45,7 @@ async function bootstrap() { app.register(fastifyCookie, { secret: process.env.JWT_SECRET }); - await app.listen(process.env.PORT ?? 3000, '0.0.0.0', () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) }); - + // await app.listen(process.env.PORT ?? 3000, '0.0.0.0', () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) }); + await app.listen(process.env.PORT || 3000, () => { process.env.NODE_ENV !== 'prod' && console.log(`service is running on ${process.env.PORT}`)}); } bootstrap(); diff --git a/src/middleware/auth/auth.service.ts b/src/middleware/auth/auth.service.ts index 6d1ce30..940bac8 100644 --- a/src/middleware/auth/auth.service.ts +++ b/src/middleware/auth/auth.service.ts @@ -6,7 +6,7 @@ export class AuthService { constructor(private readonly jwtService: JwtService) {} generateTokens(id: string) { - const accessToken = this.jwtService.sign({id: id}, { expiresIn: '5s' }); + const accessToken = this.jwtService.sign({id: id}, { expiresIn: '1m' }); const refreshToken = this.jwtService.sign({id: id}, { expiresIn: '7d' }); return { accessToken, refreshToken }; diff --git a/src/middleware/auth/guard/access-token.guard.ts b/src/middleware/auth/guard/access-token.guard.ts index 41e2077..3516a4d 100644 --- a/src/middleware/auth/guard/access-token.guard.ts +++ b/src/middleware/auth/guard/access-token.guard.ts @@ -1,6 +1,6 @@ import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; -import { TokenExpiredError } from "@nestjs/jwt"; +import { JsonWebTokenError, TokenExpiredError } from "@nestjs/jwt"; import { AuthGuard } from "@nestjs/passport"; import { IS_PUBLIC_KEY } from "src/common/decorators/public.decorator"; @@ -23,23 +23,18 @@ export class JwtAccessAuthGuard extends AuthGuard('access-token') { return super.canActivate(context); } - handleRequest(err: any, user:any, info:any) { - if (info instanceof TokenExpiredError) { - throw new UnauthorizedException({ - statusCode: 401, - message: 'Access Token Expired', - code: 'AccessTokenExpired' - }); - } - + handleRequest(err: any, user:any, info:any, context: ExecutionContext) { if (err || !user) { - throw new UnauthorizedException({ - statusCode: 401, - message: 'Invalid Token', - code: 'InvalidToken' - }); - } + if (info instanceof TokenExpiredError) { + throw info; + } + if (info instanceof JsonWebTokenError) { + throw info; + } + + throw err || new JsonWebTokenError('Unauthorized'); + } return user; } } diff --git a/src/middleware/auth/strategy/access-token.strategy.ts b/src/middleware/auth/strategy/access-token.strategy.ts index bcc2577..f61e88d 100644 --- a/src/middleware/auth/strategy/access-token.strategy.ts +++ b/src/middleware/auth/strategy/access-token.strategy.ts @@ -2,10 +2,14 @@ import { Injectable, UnauthorizedException } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { PassportStrategy } from "@nestjs/passport"; import { ExtractJwt, Strategy } from "passport-jwt"; +import { AccountRepo } from "src/modules/account/account.repo"; @Injectable() export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token") { - constructor(configService: ConfigService) { + constructor( + configService: ConfigService, + private accountRepo: AccountRepo + ) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: configService.get('JWT_SECRET')! @@ -13,10 +17,11 @@ export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token" } async validate(payload: any) { - const token = ExtractJwt.fromAuthHeaderAsBearerToken(); - if (!token) { + console.log(payload); + const user = await this.accountRepo.findById(payload.id); + if (!user) { throw new UnauthorizedException(); } - return { id: payload.id }; + return user; } } \ No newline at end of file diff --git a/src/modules/account/account.repo.ts b/src/modules/account/account.repo.ts index 58e5fea..988a017 100644 --- a/src/modules/account/account.repo.ts +++ b/src/modules/account/account.repo.ts @@ -26,7 +26,7 @@ export class AccountRepo { email: string, password: string ) { - return this + return await this .db .insert(schema.account) .values({ @@ -42,7 +42,7 @@ export class AccountRepo { type: 'email' | 'accountId' , id: string ) { - return this + return await this .db .select() .from(schema.account) diff --git a/src/modules/account/dto/checkDuplication/check-duplication-response.dto.ts b/src/modules/account/dto/checkDuplication/check-duplication-response.dto.ts index 188531c..27b2fcf 100644 --- a/src/modules/account/dto/checkDuplication/check-duplication-response.dto.ts +++ b/src/modules/account/dto/checkDuplication/check-duplication-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class CheckDuplicationResponseDto extends BaseResponseDto { isDuplicated: boolean; diff --git a/src/modules/account/dto/login/login-response.dto.ts b/src/modules/account/dto/login/login-response.dto.ts index 05892cb..df6f4e1 100644 --- a/src/modules/account/dto/login/login-response.dto.ts +++ b/src/modules/account/dto/login/login-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class LoginResponseDto extends BaseResponseDto { accessToken?: string; diff --git a/src/modules/account/dto/refreshAccessToken/refresh-access-token-response.dto.ts b/src/modules/account/dto/refreshAccessToken/refresh-access-token-response.dto.ts index 3572fb8..964295b 100644 --- a/src/modules/account/dto/refreshAccessToken/refresh-access-token-response.dto.ts +++ b/src/modules/account/dto/refreshAccessToken/refresh-access-token-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class RefreshAccessTokenResponseDto extends BaseResponseDto{ accessToken: string; diff --git a/src/modules/account/dto/resetPassword/reset-password-response.dto.ts b/src/modules/account/dto/resetPassword/reset-password-response.dto.ts index cec874f..d7b9c00 100644 --- a/src/modules/account/dto/resetPassword/reset-password-response.dto.ts +++ b/src/modules/account/dto/resetPassword/reset-password-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class ResetPasswordResponseDto extends BaseResponseDto { diff --git a/src/modules/account/dto/sendEmailVerificationCode/send-email-verification-code-response.dto.ts b/src/modules/account/dto/sendEmailVerificationCode/send-email-verification-code-response.dto.ts index ac53990..4d97930 100644 --- a/src/modules/account/dto/sendEmailVerificationCode/send-email-verification-code-response.dto.ts +++ b/src/modules/account/dto/sendEmailVerificationCode/send-email-verification-code-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class SendEmailVerificationCodeResponseDto extends BaseResponseDto{ } \ No newline at end of file diff --git a/src/modules/account/dto/sendResetPasswordCode/send-reset-password-code-response.dto.ts b/src/modules/account/dto/sendResetPasswordCode/send-reset-password-code-response.dto.ts index c883b72..794132b 100644 --- a/src/modules/account/dto/sendResetPasswordCode/send-reset-password-code-response.dto.ts +++ b/src/modules/account/dto/sendResetPasswordCode/send-reset-password-code-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class SendResetPasswordCodeResponseDto extends BaseResponseDto { } \ No newline at end of file diff --git a/src/modules/account/dto/signup/signup-response.dto.ts b/src/modules/account/dto/signup/signup-response.dto.ts index 60fe8d3..309cb03 100644 --- a/src/modules/account/dto/signup/signup-response.dto.ts +++ b/src/modules/account/dto/signup/signup-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class SignupResponseDto extends BaseResponseDto { } \ No newline at end of file diff --git a/src/modules/account/dto/verifyEmailVerificationCode/verify-email-verification-code-response.dto.ts b/src/modules/account/dto/verifyEmailVerificationCode/verify-email-verification-code-response.dto.ts index 174ec1f..6ca02ba 100644 --- a/src/modules/account/dto/verifyEmailVerificationCode/verify-email-verification-code-response.dto.ts +++ b/src/modules/account/dto/verifyEmailVerificationCode/verify-email-verification-code-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class VerifyEmailVerificationCodeResponseDto extends BaseResponseDto{ verified: boolean; diff --git a/src/modules/account/dto/verifyResetPasswordCode/verify-reset-password-code-response.dto.ts b/src/modules/account/dto/verifyResetPasswordCode/verify-reset-password-code-response.dto.ts index b76b3a8..a19d450 100644 --- a/src/modules/account/dto/verifyResetPasswordCode/verify-reset-password-code-response.dto.ts +++ b/src/modules/account/dto/verifyResetPasswordCode/verify-reset-password-code-response.dto.ts @@ -1,4 +1,4 @@ -import { BaseResponseDto } from "../base-response.dto"; +import { BaseResponseDto } from "../../../../common/dto/base-response.dto"; export class VerifyResetPasswordCodeResponseDto extends BaseResponseDto { verified: boolean;