114 lines
2.5 KiB
JavaScript
114 lines
2.5 KiB
JavaScript
/**
|
|
* Copyright (c) 2026 Niolla
|
|
* All rights reserved.
|
|
*
|
|
* This source code is proprietary and confidential.
|
|
* Unauthorized copying, modification, distribution, or use
|
|
* of this file, via any medium, is strictly prohibited.
|
|
*/
|
|
|
|
// app/utils/passwordReset.util.js
|
|
|
|
const crypto = require("crypto");
|
|
|
|
const createRedisConnection = require("../config/redis.config");
|
|
const redis = createRedisConnection();
|
|
|
|
const db = require("../models");
|
|
|
|
const User = db.User;
|
|
|
|
const { log } = require("./consoleLog.utill");
|
|
const { hashPassword } = require("./hashPassword.util");
|
|
|
|
const RESET_TOKEN_TTL = process.env.RESET_TOKEN_TTL || 10 * 60; // 10 minutes
|
|
|
|
/**
|
|
* Generate password reset token
|
|
*
|
|
* @param {string} userId
|
|
* @returns {Promise<string>}
|
|
*/
|
|
async function generateResetToken(userId) {
|
|
try {
|
|
const token = crypto.randomBytes(32).toString("hex");
|
|
|
|
const tokenHash = crypto
|
|
.createHash("sha256")
|
|
.update(token)
|
|
.digest("hex");
|
|
|
|
await redis.set(
|
|
`passwordReset:user:${userId}`,
|
|
tokenHash,
|
|
"EX",
|
|
RESET_TOKEN_TTL
|
|
);
|
|
log(`Generated password reset token for user ${userId} with TTL of ${RESET_TOKEN_TTL} seconds, Generated token:`, token);
|
|
return token;
|
|
} catch (error) {
|
|
log("Password reset token generation failed", error);
|
|
throw new Error("Failed to generate password reset token");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset password using token
|
|
*
|
|
* @param {string} userId
|
|
* @param {string} token
|
|
* @param {string} newPassword
|
|
*/
|
|
async function resetPassword(userId, token, newPassword) {
|
|
try {
|
|
const storedHash = await redis.get(
|
|
`passwordReset:user:${userId}`
|
|
);
|
|
|
|
if (!storedHash) {
|
|
throw new Error("Invalid or expired reset token");
|
|
}
|
|
|
|
const tokenHash = crypto
|
|
.createHash("sha256")
|
|
.update(token)
|
|
.digest("hex");
|
|
|
|
const isValid =
|
|
crypto.timingSafeEqual(
|
|
Buffer.from(storedHash),
|
|
Buffer.from(tokenHash)
|
|
);
|
|
|
|
if (!isValid) {
|
|
throw new Error("Invalid or expired reset token");
|
|
}
|
|
|
|
const user = await User.findByPk(userId);
|
|
|
|
if (!user) {
|
|
throw new Error("User not found");
|
|
}
|
|
|
|
user.password = await hashPassword(newPassword);
|
|
|
|
await user.save();
|
|
|
|
await redis.del(`passwordReset:user:${userId}`);
|
|
|
|
log(
|
|
`Password reset completed successfully for user ${userId}`
|
|
);
|
|
|
|
return true;
|
|
} catch (error) {
|
|
log("Password reset failed", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
generateResetToken,
|
|
resetPassword
|
|
};
|