first commit
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
Reference in New Issue
Block a user