From 3c6f7b5a7992e34e198142bea8c81094ee9a4283 Mon Sep 17 00:00:00 2001 From: Rwirangira <142627846+A-gent64@users.noreply.github.com> Date: Tue, 30 Apr 2024 21:58:44 +0200 Subject: [PATCH] [Finishes #187354251] Update user password --- src/controllers/authController.ts | 48 ++++++++++++++++- src/docs/auth.yaml | 85 ++++++++++++++++++++++++++++-- src/middlewares/authMiddlewares.ts | 1 + src/routes/authRoute.ts | 8 +-- 4 files changed, 135 insertions(+), 7 deletions(-) diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts index e601588c..e4fb26ff 100644 --- a/src/controllers/authController.ts +++ b/src/controllers/authController.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unnecessary-condition */ import { Request, Response, NextFunction } from 'express'; import passport from 'passport'; import jwt from 'jsonwebtoken'; @@ -5,6 +7,7 @@ import bcrypt from 'bcrypt'; import User, { UserAttributes } from '../database/models/user'; import { sendInternalErrorResponse, validateFields } from '../validations'; import logger from '../logs/config'; +import { UUID } from 'crypto'; const authenticateViaGoogle = (req: Request, res: Response, next: NextFunction) => { passport.authenticate('google', (err: unknown, user: UserAttributes | null) => { @@ -93,5 +96,48 @@ const login = async (req: Request, res: Response): Promise => { sendInternalErrorResponse(res, err); } }; +const updatePassword = async (req: Request, res: Response): Promise => { + try { + const { oldPassword, newPassword } = req.body; + + // Access decoded user information from the request object + const user = req?.user as { + id: UUID; + password: string; + }; + + // Check if old password matches + const match = await bcrypt.compare(oldPassword, user.password); + if (!match) { + res.status(400).json({ + ok: false, + message: 'The old password is incorrect!', + }); + return; + } + + // Generate salt and hash new password + const saltRound = await bcrypt.genSalt(10); + const hashedNewPassword = await bcrypt.hash(newPassword, saltRound); + + // Update user's password + await User.update( + { password: hashedNewPassword }, + { + where: { + id: user.id, + }, + } + ); + + res.status(200).json({ + ok: true, + message: 'Successfully updated user password!', + }); + } catch (error) { + logger.error('Error updating user:', error); + sendInternalErrorResponse(res, error); + } +}; -export { login, authenticateViaGoogle }; +export { login, updatePassword, authenticateViaGoogle }; diff --git a/src/docs/auth.yaml b/src/docs/auth.yaml index 7e86524c..9a096c37 100644 --- a/src/docs/auth.yaml +++ b/src/docs/auth.yaml @@ -1,3 +1,4 @@ + paths: /api/auth/google: @@ -53,6 +54,84 @@ paths: 500: description: Internal server error -tags: - - name: Login - description: Login a user + /api/auth/update-password: + put: + summary: Update user password + description: Updates the password of the authenticated user. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + oldPassword: + type: string + description: The current password of the user. + newPassword: + type: string + description: The new password to be set for the user. + required: + - oldPassword + - newPassword + responses: + '200': + description: Successfully updated user password. + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + description: Indicates if the operation was successful. + example: true + message: + type: string + description: A message indicating the status of the operation. + example: Successfully updated user password! + '400': + description: Bad request. Indicates that the provided token is invalid or old password is incorrect, or the user is not found. + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + description: Indicates if the operation was successful. + example: false + message: + type: string + description: A message indicating the reason for the failure. + example: Invalid token + '401': + description: Unauthorized. Indicates that no token was provided. + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + description: Indicates if the operation was successful. + example: false + message: + type: string + description: A message indicating the reason for the failure. + example: Unauthorized + '500': + description: Internal Server Error. Indicates an unexpected error occurred. + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + description: Indicates if the operation was successful. + example: false + message: + type: string + description: A message indicating the reason for the failure. + example: Internal Server Error \ No newline at end of file diff --git a/src/middlewares/authMiddlewares.ts b/src/middlewares/authMiddlewares.ts index ed474de5..0ef60b08 100644 --- a/src/middlewares/authMiddlewares.ts +++ b/src/middlewares/authMiddlewares.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-misused-promises */ import { Request, Response, NextFunction } from 'express'; import { config } from 'dotenv'; diff --git a/src/routes/authRoute.ts b/src/routes/authRoute.ts index d6c7fdc4..80f4ba7c 100644 --- a/src/routes/authRoute.ts +++ b/src/routes/authRoute.ts @@ -1,8 +1,8 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ import { Router } from 'express'; import passport from 'passport'; -import { authenticateViaGoogle } from '../controllers/authController'; -import { login } from '../controllers/authController'; - +import { authenticateViaGoogle, login, updatePassword } from '../controllers/authController'; +import { isAuthenticated } from '../middlewares/authMiddlewares'; const router = Router(); // redirect user to google for authentication router.get( @@ -18,4 +18,6 @@ router.get('/google/callback', authenticateViaGoogle); // Route to login a user router.post('/login', login); +router.put('/update-password', isAuthenticated, updatePassword); + export default router;