changed model

This commit is contained in:
unknown 2025-12-31 15:17:18 +05:30
parent e5bca1f2e9
commit 2d712682cf
3 changed files with 142 additions and 189 deletions

View File

@ -1051,157 +1051,156 @@ exports.forgotPasswordVerifyOTP = async (req, res) => {
}; };
exports.requestOTPForLogin = async (req, res) => { exports.requestOTPForLogin = async (req, res) => {
try { // try {
const { registered_email } = req.body; // const { registered_email } = req.body;
if (!registered_email) { // if (!registered_email) {
return res.status(400).json({ // return res.status(400).json({
status: "failed", // status: "failed",
message: "Email is required", // message: "Email is required",
}); // });
} // }
// Check which model contains the user // // Check which model contains the user
let loggingUser = await EstablishmentUser.findOne({ // let loggingUser = await EstablishmentUser.findOne({
where: { email: registered_email } // where: { email: registered_email }
}); // });
let userModel = EstablishmentUser; // let userModel = EstablishmentUser;
if (!loggingUser) { // if (!loggingUser) {
loggingUser = await User.findOne({ // loggingUser = await User.findOne({
where: { email: registered_email, is_active: true } // where: { email: registered_email, is_active: true }
}); // });
userModel = User; // userModel = User;
} // }
if (!loggingUser) { // if (!loggingUser) {
logger.warn(`OTP requested for non-existing email: ${sanitizeForLog(registered_email)}`); // logger.warn(`OTP requested for non-existing email: ${sanitizeForLog(registered_email)}`);
return res.status(404).json({ // return res.status(404).json({
status: "failed", // status: "failed",
message: "Invalid login request. Please check your email or register to continue.", // message: "Invalid login request. Please check your email or register to continue.",
}); // });
} // }
// Secure OTP generation // // Secure OTP generation
const otp = crypto.randomInt(100000, 999999).toString(); // const otp = crypto.randomInt(100000, 999999).toString();
// Hash OTP before storing // // Hash OTP before storing
const hashedOtp = await bcrypt.hash(otp, 10); // const hashedOtp = await bcrypt.hash(otp, 10);
// Store OTP in the correct model with WHERE clause // // Store OTP in the correct model with WHERE clause
await userModel.update( // await userModel.update(
{ // {
login_otp: hashedOtp, // login_otp: hashedOtp,
login_otp_expires_at: new Date(Date.now() + 10 * 60 * 1000), // login_otp_expires_at: new Date(Date.now() + 10 * 60 * 1000),
}, // },
{ // {
where: { email: registered_email } // where: { email: registered_email }
} // }
); // );
const placeHolderData = { // const placeHolderData = {
username: loggingUser.name, // username: loggingUser.name,
verfication_code: otp, // verfication_code: otp,
support_email: process.env.SUPPORT_EMAIL, // support_email: process.env.SUPPORT_EMAIL,
support_phone: process.env.SUPPORT_PHONE // support_phone: process.env.SUPPORT_PHONE
}; // };
await sendEmailService(registered_email, "sign_in_verification_code", placeHolderData); // await sendEmailService(registered_email, "sign_in_verification_code", placeHolderData);
logger.info(`Login OTP email triggered for: ${sanitizeForLog(registered_email)}`); // logger.info(`Login OTP email triggered for: ${sanitizeForLog(registered_email)}`);
return res.status(200).json({ // return res.status(200).json({
status: "success", // status: "success",
message: "OTP sent successfully to your registered email", // message: "OTP sent successfully to your registered email",
}); // });
} catch (err) { // } catch (err) {
logger.error(`OTP request failed: ${err.message}`); // logger.error(`OTP request failed: ${err.message}`);
logger.error(err.stack); // logger.error(err.stack);
return res.status(500).json({ // return res.status(500).json({
status: "failed", // status: "failed",
message: "Internal Server Error", // message: "Internal Server Error",
}); // });
} // }
}; };
exports.verifyOTPForLogin = async (req, res) => { exports.verifyOTPForLogin = async (req, res) => {
try { // try {
const { registered_email, otp } = req.body; // const { registered_email, otp } = req.body;
// Validation // if (!registered_email || !otp) {
if (!registered_email || !otp) { // return res.status(400).json({
return res.status(400).json({ // status: "failed",
status: "failed", // message: "Email and OTP are required"
message: "Email and OTP are required" // });
}); // }
}
// Find user from either model // // Find user from either model
let user = await EstablishmentUser.scope("withSensitive").findOne({ // let user = await EstablishmentUser.scope("withSensitive").findOne({
where: { email: registered_email } // where: { email: registered_email }
}); // });
if (!user) { // if (!user) {
user = await User.scope("withSensitive").findOne({ // user = await User.scope("withSensitive").findOne({
where: { email: registered_email, is_active: true } // where: { email: registered_email, is_active: true }
}); // });
} // }
// User validation // // User validation
if (!user) { // if (!user) {
return res.status(404).json({ // return res.status(404).json({
status: "failed", // status: "failed",
message: "User not found" // message: "User not found"
}); // });
} // }
if (!user.login_otp) { // if (!user.login_otp) {
return res.status(404).json({ // return res.status(404).json({
status: "failed", // status: "failed",
message: "Verification code not found or invalid user" // message: "Verification code not found or invalid user"
}); // });
} // }
// Check OTP expiry // // Check OTP expiry
if (new Date() > new Date(user.login_otp_expires_at)) { // if (new Date() > new Date(user.login_otp_expires_at)) {
return res.status(400).json({ // return res.status(400).json({
status: "failed", // status: "failed",
message: "Verification code has expired. Please request a new one" // message: "Verification code has expired. Please request a new one"
}); // });
} // }
// Verify OTP // // Verify OTP
const isOtpValid = await bcrypt.compare(otp, user.login_otp); // const isOtpValid = await bcrypt.compare(otp, user.login_otp);
if (!isOtpValid) { // if (!isOtpValid) {
return res.status(400).json({ // return res.status(400).json({
status: "failed", // status: "failed",
message: "Invalid verification code" // message: "Invalid verification code"
}); // });
} // }
// Clear OTP after successful verification // // Clear OTP after successful verification
await user.update({ // await user.update({
login_otp: null, // login_otp: null,
login_otp_expires_at: null, // login_otp_expires_at: null,
}); // });
const safeEmail = sanitizeForLog(registered_email); // const safeEmail = sanitizeForLog(registered_email);
logger.info(`OTP verification successful for user: ${safeEmail}`); // logger.info(`OTP verification successful for user: ${safeEmail}`);
return res.status(200).json({ // return res.status(200).json({
status: "success", // status: "success",
message: "Email verified successfully!", // message: "Email verified successfully!",
}); // });
} catch (err) { // } catch (err) {
logger.error(`OTP verification error: ${err.message}`); // logger.error(`OTP verification error: ${err.message}`);
logger.error(`Stack trace: ${err.stack}`); // logger.error(`Stack trace: ${err.stack}`);
return res.status(500).json({ // return res.status(500).json({
status: "failed", // status: "failed",
message: "Internal server error" // message: "Internal server error"
}); // });
} // }
}; };
const GENERIC_ERROR_MSG = const GENERIC_ERROR_MSG =

View File

@ -75,63 +75,40 @@ module.exports = (sequelize, DataTypes) => {
}, },
}, },
{ {
login_otp: { // ============================================================
type: DataTypes.STRING, // Model Options
allowNull: true, // ============================================================
},
login_otp_expires_at: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
timestamps: false, timestamps: false,
tableName: "establishment_users", tableName: "establishment_users",
// Hide sensitive fields by default // 1. Hide sensitive fields by default
defaultScope: { defaultScope: {
attributes: { attributes: {
exclude: [ exclude: ["password", "reset_otp", "reset_otp_expires_at"],
"password",
"reset_otp",
"reset_otp_expires_at",
"login_otp",
"login_otp_expires_at",
],
}, },
}, },
// Scope for login & sensitive operations // 2. Scope for login / sensitive queries
scopes: { scopes: {
withSensitive: { withSensitive: {
attributes: { attributes: {
include: [ include: ["password", "reset_otp", "reset_otp_expires_at"],
"password",
"reset_otp",
"reset_otp_expires_at",
"login_otp",
"login_otp_expires_at",
],
}, },
}, },
}, },
} }
); );
// 3. Remove sensitive fields from all API responses
EstablishmentUser.prototype.toJSON = function () { EstablishmentUser.prototype.toJSON = function () {
const values = { ...this.get() }; const values = { ...this.get() };
delete values.password; delete values.password;
delete values.reset_otp; delete values.reset_otp;
delete values.reset_otp_expires_at; delete values.reset_otp_expires_at;
delete values.login_otp;
delete values.login_otp_expires_at;
return values; return values;
}; };
// ==================================================== // Relationships
// Associations
// ====================================================
EstablishmentUser.associate = (models) => { EstablishmentUser.associate = (models) => {
EstablishmentUser.belongsTo(models.Establishment, { EstablishmentUser.belongsTo(models.Establishment, {
foreignKey: "establishment_id", foreignKey: "establishment_id",

View File

@ -32,32 +32,15 @@ module.exports = (sequelize, DataTypes) => {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: true, allowNull: true,
}, },
login_otp: {
type: DataTypes.STRING,
allowNull: true,
},
login_otp_expires_at: {
type: DataTypes.DATE,
allowNull: true,
},
is_active: { is_active: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
defaultValue: true, defaultValue: true,
}, },
}, },
{ {
// 1. EXCLUDE sensitive fields from all queries
defaultScope: { defaultScope: {
attributes: { attributes: { exclude: ["password", "reset_otp", "reset_otp_expires_at"] },
exclude: [
"password",
"reset_otp",
"reset_otp_expires_at",
"login_otp",
"login_otp_expires_at",
],
},
}, },
// ------------------------------------------------------------- // -------------------------------------------------------------
@ -67,13 +50,7 @@ module.exports = (sequelize, DataTypes) => {
scopes: { scopes: {
withSensitive: { withSensitive: {
attributes: { attributes: {
include: [ include: ["password", "reset_otp", "reset_otp_expires_at"],
"password",
"reset_otp",
"reset_otp_expires_at",
"login_otp",
"login_otp_expires_at",
],
}, },
}, },
}, },
@ -81,4 +58,4 @@ module.exports = (sequelize, DataTypes) => {
); );
return User; return User;
}; };