diff --git a/src/helpers/error/handler/index.ts b/src/helpers/error/handler/index.ts index 2a572c9..6011572 100644 --- a/src/helpers/error/handler/index.ts +++ b/src/helpers/error/handler/index.ts @@ -51,5 +51,5 @@ export const mainErrorHandler = (set: Context["set"], error: unknown) => { ); } - return returnErrorResponse(set, 500, "Internal server error"); + return returnErrorResponse(set, 500, "Internal server error", error); }; diff --git a/src/helpers/security/password/compare.ts b/src/helpers/security/password/compare.ts new file mode 100644 index 0000000..3b141a3 --- /dev/null +++ b/src/helpers/security/password/compare.ts @@ -0,0 +1,13 @@ +import { AppError } from "../../error/instances/app"; +import bcrypt from "bcrypt"; + +export const comparePassword = async ( + passwordInput: string, + passwordRaw: string +) => { + try { + return bcrypt.compare(passwordInput, passwordRaw); + } catch (error) { + throw new AppError(401, "Invalid credentials", error); + } +}; diff --git a/src/modules/auth/services/loginWithPassword.service.ts b/src/modules/auth/services/loginWithPassword.service.ts index f652d55..cc32f1c 100644 --- a/src/modules/auth/services/loginWithPassword.service.ts +++ b/src/modules/auth/services/loginWithPassword.service.ts @@ -13,7 +13,10 @@ export const loginWithPasswordService = async ( ) => { try { // search for user data using an identifier (username or email) - const userData = await findUserByEmailOrUsernameService(request.identifier); + const userData = await findUserByEmailOrUsernameService( + request.identifier, + { verbose: true } + ); // if user data is not found, throw an error if (!userData) throw new AppError(404, "User not found"); diff --git a/src/modules/user/controller/checkUserPassword.controller.ts b/src/modules/user/controller/checkUserPassword.controller.ts index 976d1ff..02183cd 100644 --- a/src/modules/user/controller/checkUserPassword.controller.ts +++ b/src/modules/user/controller/checkUserPassword.controller.ts @@ -2,11 +2,26 @@ import { Context } from "elysia"; import { checkUserPasswordService } from "../services/checkUserPassword.service"; import { jwtDecode } from "../../../helpers/http/jwt/decode"; import { getCookie } from "../../../helpers/http/userHeader/cookies/getCookies"; +import { mainErrorHandler } from "../../../helpers/error/handler"; +import { returnWriteResponse } from "../../../helpers/callback/httpResponse"; export const checkUserPasswordController = async ( ctx: Context & { body: { password: string } } ) => { - const cookie = getCookie(ctx); - const jwtPayload = jwtDecode(cookie.auth_token!); - return checkUserPasswordService(jwtPayload, ctx.body.password); + try { + const cookie = getCookie(ctx); + const jwtPayload = jwtDecode(cookie.auth_token!); + const checkUserPassword = await checkUserPasswordService( + jwtPayload.user.username, + ctx.body.password + ); + return returnWriteResponse( + ctx.set, + 204, + "Password is valid", + checkUserPassword + ); + } catch (error) { + return mainErrorHandler(ctx.set, error); + } }; diff --git a/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts b/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts index 7654c0e..806761e 100644 --- a/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts +++ b/src/modules/user/repositories/findUserByEmailOrUsername.repository.ts @@ -1,16 +1,20 @@ +import { FindUserByEmailOrUsernameOptions } from "../services/findUserByEmailOrUsername.service"; import { userModel } from "../user.model"; -export const findUserByEmailOrUsernameRepo = async (identifier: string) => { +export const findUserByEmailOrUsernameRepo = async ( + identifier: string, + options: FindUserByEmailOrUsernameOptions +) => { const userData = (await userModel.findUnique({ where: { email: identifier }, include: { roles: { omit: { - createdBy: true, - createdAt: true, - updatedAt: true, - deletedAt: true, + createdBy: !options.verbose, + createdAt: !options.verbose, + updatedAt: !options.verbose, + deletedAt: !options.verbose, }, }, }, @@ -20,10 +24,10 @@ export const findUserByEmailOrUsernameRepo = async (identifier: string) => { include: { roles: { omit: { - createdBy: true, - createdAt: true, - updatedAt: true, - deletedAt: true, + createdBy: !options.verbose, + createdAt: !options.verbose, + updatedAt: !options.verbose, + deletedAt: !options.verbose, }, }, }, diff --git a/src/modules/user/services/checkUserPassword.service.ts b/src/modules/user/services/checkUserPassword.service.ts index 6ca3e97..7b0ae6d 100644 --- a/src/modules/user/services/checkUserPassword.service.ts +++ b/src/modules/user/services/checkUserPassword.service.ts @@ -1,8 +1,26 @@ -import { JWTAuthToken } from "../../../helpers/http/jwt/decode/types"; +import { AppError } from "../../../helpers/error/instances/app"; +import { ErrorForwarder } from "../../../helpers/error/instances/forwarder"; +import { comparePassword } from "../../../helpers/security/password/compare"; +import { findUserByEmailOrUsernameService } from "./findUserByEmailOrUsername.service"; +import { User } from "@prisma/client"; export const checkUserPasswordService = async ( - jwtPayload: JWTAuthToken, + username: string, password: string ) => { - return `id user "${jwtPayload.userId}" cek password "${password}"`; + try { + const userData = (await findUserByEmailOrUsernameService(username, { + verbose: true, + })) as User; + const RawPassword = userData.password; + + const matchingPassword = await comparePassword(password, RawPassword); + if (!matchingPassword) { + throw new AppError(401, "Invalid Credential"); + } + + return true; + } catch (error) { + ErrorForwarder(error); + } }; diff --git a/src/modules/user/services/findUserByEmailOrUsername.service.ts b/src/modules/user/services/findUserByEmailOrUsername.service.ts index 8739b8c..c95f097 100644 --- a/src/modules/user/services/findUserByEmailOrUsername.service.ts +++ b/src/modules/user/services/findUserByEmailOrUsername.service.ts @@ -1,9 +1,19 @@ +import { AppError } from "../../../helpers/error/instances/app"; import { ErrorForwarder } from "../../../helpers/error/instances/forwarder"; import { findUserByEmailOrUsernameRepo } from "../repositories/findUserByEmailOrUsername.repository"; -export const findUserByEmailOrUsernameService = async (identifier: string) => { +export interface FindUserByEmailOrUsernameOptions { + verbose?: boolean; +} + +export const findUserByEmailOrUsernameService = async ( + identifier: string, + options: FindUserByEmailOrUsernameOptions = {} +) => { try { - const userData = await findUserByEmailOrUsernameRepo(identifier); + const userData = await findUserByEmailOrUsernameRepo(identifier, options); + if (!userData) throw new AppError(404, "User not found"); + return userData; } catch (error) { ErrorForwarder(error);