Skip to content

Commit

Permalink
[finishes #187354249] reset password via email
Browse files Browse the repository at this point in the history
  • Loading branch information
princenzmw committed May 11, 2024
1 parent 92a721f commit cd08408
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 46 deletions.
77 changes: 75 additions & 2 deletions src/controllers/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import { Request, Response, NextFunction } from 'express';
import passport from 'passport';
import jwt, { JwtPayload } from 'jsonwebtoken';
import User, { UserAttributes } from '../database/models/user';
import { sendInternalErrorResponse, validateFields } from '../validations';
import { sendInternalErrorResponse, validateFields, validatePassword } from '../validations';
import logger from '../logs/config';
import { passwordCompare } from '../helpers/encrypt';
import { verifyIfSeller } from '../middlewares/authMiddlewares';
import { createOTPToken, saveOTPDB } from '../middlewares/otpAuthMiddleware';
import { userToken } from '../helpers/token.generator';
import { userToken, verifyToken } from '../helpers/token.generator';
import { sendErrorResponse } from '../helpers/helper';
// Additional imports
import { sendEmail } from '../helpers/send-email';
import { passwordEncrypt } from '../helpers/encrypt';

export const authenticateViaGoogle = (req: Request, res: Response, next: NextFunction) => {
passport.authenticate('google', (err: unknown, user: UserAttributes | null) => {
Expand Down Expand Up @@ -119,3 +122,73 @@ export const sendOTP = async (req: Request, res: Response, email: string) => {
}
}
};

// Function to Request Password reset token
export const forgotPassword = async (req: Request, res: Response) => {
try {
const { email } = req.body;

// Verify if user exists
const user = await User.findOne({ where: { email } });
if (!user) {
return res.status(404).json({ ok: false, error: 'User with this email does not exist' });
}

// Generate reset token
const token = await userToken(user.id, user.email);

// Send email with token
const link = `${process.env.URL_HOST}:${process.env.PORT}/api/auth/reset-password/${token}`;

await sendEmail('reset_password', {
name: `${user.firstName} ${user.lastName}`,
email: `${user.email}`,
link: link,
});

return res.status(200).json({
ok: true,
message: 'A password reset link has been sent to your email.',
});
} catch (error) {
logger.error('Error requesting password reset: ', error);
sendInternalErrorResponse(res, error);
return;
}
};

// Function to Reset Password
export const resetPassword = async (req: Request, res: Response) => {
try {
const { newPassword } = req.body;

const userId = (req.user as User).id;
// Find user
const user = await User.findOne({ where: { id: userId } });
if (!user) {
return res.status(404).json({ ok: false, error: 'User does not exist' });
}

if (!validatePassword(newPassword)) {
return res.status(400).json({
ok: false,
error: 'Password must contain at least 1 letter, 1 number, and 1 special character, minumun 8 characters',
});
}

// Hash new password
const hashPassword = await passwordEncrypt(newPassword);

// Update user's password
await user.update({ password: hashPassword });

return res.status(200).json({
ok: true,
message: 'Password reset successfully',
});
} catch (error) {
logger.error('Error resetting password: ', error);
sendInternalErrorResponse(res, error);
return;
}
};
2 changes: 1 addition & 1 deletion src/controllers/userController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const signupUser = async (req: Request, res: Response) => {
if (!validatePassword(password)) {
return res.status(400).json({
ok: false,
error: 'Ensuring it contains at least 1 letter, 1 number, and 1 special character, minumun 8 characters',
error: 'Password contains at least 1 letter, 1 number, and 1 special character, minumun 8 characters',
});
}

Expand Down
99 changes: 90 additions & 9 deletions src/docs/auth.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
paths:

/api/auth/google:
get:
summary: Authenticate with Google
Expand All @@ -16,7 +15,7 @@ paths:
/api/auth/login:
post:
summary: User Login
tags:
tags:
- Login
description: Authenticate user email and password and generate access token
requestBody:
Expand Down Expand Up @@ -48,16 +47,16 @@ paths:
description: Access token for authentication
400:
description: Invalid request parameters
404:
404:
description: User not found or incorrect credentials
500:
description: Internal server error
/api/auth/{token}/otp:
post:
summary: "Endpoint to verify OTP sent to you"
summary: 'Endpoint to verify OTP sent to you'
tags:
- Login
parameters:
parameters:
- in: path
name: token
required: true
Expand All @@ -74,14 +73,96 @@ paths:
type: string
responses:
200:
description: "Get new to token for login"
description: 'Get new to token for login'
404:
description: "No user sent token"
description: 'No user sent token'
400:
description: "OTP Enter is wrong"
description: 'OTP Enter is wrong'
403:
description: "Token expired"
description: 'Token expired'

/api/auth/forgot-password:
post:
summary: Request Password Reset
tags:
- Password Reset
description: |
Allows users to request a password reset link. The user must provide their email address. If the user exists, a password reset link will be sent to the provided email.
requestBody:
description: User's email address to request a password reset link
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
description: User's email address
responses:
200:
description: Password reset link sent successfully
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
message:
type: string
description: Confirmation message indicating the email was sent
404:
description: User with this email does not exist
500:
description: Internal server error

/api/auth/reset-password/{token}:
post:
summary: Reset Password
tags:
- Password Reset
description: |
Allows users to reset their password using a valid token received in the password reset link. The token is passed as a URL parameter, and the new password is provided by the user in the request body.
parameters:
- in: path
name: token
required: true
schema:
type: string
description: Token received for resetting password via email
requestBody:
description: New password to be set for the user
required: true
content:
application/json:
schema:
type: object
properties:
newPassword:
type: string
description: User's new password
responses:
200:
description: Password reset successfully
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
message:
type: string
description: Confirmation message indicating the password reset was successful
404:
description: Password reset token is invalid or has expired, or user does not exist
500:
description: Internal server error

tags:
- name: Login
description: Login a user
- name: Password Reset
description: Endpoints for password recovery and reset functionality
Loading

0 comments on commit cd08408

Please sign in to comment.