Implement password reset and change features with email notifications
This commit is contained in:
@@ -9,8 +9,12 @@
|
||||
|
||||
// app/controllers/auth.controller.js
|
||||
|
||||
const { checkPassword } = require("../utils/hashPassword.util");
|
||||
const { checkPassword, hashPassword } = require("../utils/hashPassword.util");
|
||||
const { sendMail } = require("../utils/mail.util");
|
||||
const {
|
||||
validatePassword,
|
||||
} = require("../utils/validation/validatePassword.util");
|
||||
const { validateEmail } = require("../utils/validation/validateEmail.util");
|
||||
const { generateOTP, validateOTP } = require("../utils/otp.util");
|
||||
const { getCachedUser, clearUserCache } = require("../utils/cache.util");
|
||||
const { generateToken } = require("../utils/jwt.util");
|
||||
@@ -18,7 +22,15 @@ const {
|
||||
createRefreshSession,
|
||||
validateRefreshSession,
|
||||
deleteRefreshSession,
|
||||
deleteAllUserSessions,
|
||||
} = require("../utils/refreshSession.util");
|
||||
const {
|
||||
createPasswordReset,
|
||||
verifyPasswordResetToken,
|
||||
deletePasswordReset,
|
||||
sendPasswordResetEmail,
|
||||
sendPasswordChangedEmail
|
||||
} = require("../utils/passwordReset.utill");
|
||||
const db = require("../models");
|
||||
const { log } = require("../utils/consoleLog.utill");
|
||||
|
||||
@@ -227,6 +239,204 @@ exports.refreshToken = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
exports.forgotPassword = async (req, res) => {
|
||||
try {
|
||||
let { email } = req.body;
|
||||
|
||||
if (!email) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message: "Email is required",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
email = email.trim().toLowerCase();
|
||||
|
||||
if (!validateEmail(email)) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message: "Invalid email address",
|
||||
});
|
||||
}
|
||||
|
||||
const user = await User.findOne({
|
||||
where: { email },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(200).send({
|
||||
success: true,
|
||||
message:
|
||||
"If an account exists for this email, a password reset link has been sent.",
|
||||
});
|
||||
}
|
||||
|
||||
const resetToken = await createPasswordReset(user.id);
|
||||
|
||||
await sendPasswordResetEmail(user.email, user.firstName, resetToken);
|
||||
|
||||
return res.status(200).send({
|
||||
success: true,
|
||||
message:
|
||||
"If an account exists for this email, a password reset link has been sent.",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("FORGOT PASSWORD ERROR:", error);
|
||||
|
||||
return res.status(500).send({
|
||||
success: false,
|
||||
message: "Unable to process password reset request",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.resetPassword = async (req, res) => {
|
||||
|
||||
try {
|
||||
|
||||
const {
|
||||
token,
|
||||
newPassword,
|
||||
confirmPassword,
|
||||
} = req.body;
|
||||
|
||||
|
||||
if (!token ||!newPassword || !confirmPassword) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message:
|
||||
"Token, new password and confirm password are required",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
newPassword !==
|
||||
confirmPassword
|
||||
) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message:
|
||||
"Passwords do not match",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!validatePassword(newPassword)
|
||||
) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message:
|
||||
"Password does not meet the required criteria",
|
||||
});
|
||||
}
|
||||
|
||||
const verification =
|
||||
await verifyPasswordResetToken(
|
||||
token
|
||||
);
|
||||
|
||||
|
||||
if (!verification) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message:
|
||||
"Reset token is invalid or expired",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const {
|
||||
userId,
|
||||
redisKey,
|
||||
} = verification;
|
||||
|
||||
const user =
|
||||
await User.findByPk(userId);
|
||||
|
||||
|
||||
if (!user) {
|
||||
|
||||
await deletePasswordReset(
|
||||
redisKey
|
||||
);
|
||||
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message:
|
||||
"Reset token is invalid or expired",
|
||||
});
|
||||
}
|
||||
|
||||
const samePassword =
|
||||
await checkPassword(
|
||||
newPassword,
|
||||
user.password
|
||||
);
|
||||
|
||||
|
||||
if (samePassword) {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
message:
|
||||
"New password must be different from the current password",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const hashedPassword =
|
||||
await hashPassword(
|
||||
newPassword
|
||||
);
|
||||
|
||||
|
||||
user.password =
|
||||
hashedPassword;
|
||||
|
||||
user.passwordChangedAt =
|
||||
new Date();
|
||||
|
||||
|
||||
await user.save();
|
||||
|
||||
await sendPasswordChangedEmail(
|
||||
user.email,
|
||||
user.firstName
|
||||
);
|
||||
|
||||
await deletePasswordReset(
|
||||
redisKey
|
||||
);
|
||||
|
||||
deleteAllUserSessions(
|
||||
user.id
|
||||
);
|
||||
|
||||
|
||||
return res.status(200).send({
|
||||
success: true,
|
||||
message:
|
||||
"Password reset successfully. Please login again.",
|
||||
});
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.error(
|
||||
"RESET PASSWORD ERROR:",
|
||||
error
|
||||
);
|
||||
|
||||
|
||||
return res.status(500).send({
|
||||
success: false,
|
||||
message:
|
||||
"Failed to reset password",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Logout: Clear the JWT cookie
|
||||
exports.logout = (req, res) => {
|
||||
res.clearCookie("access_token", {
|
||||
|
||||
Reference in New Issue
Block a user