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;
// if (!registered_email || !otp) {
// return res.status(400).json({
// status: "failed",
// message: "Email and OTP are required"
// });
// }
// Validation // // Find user from either model
if (!registered_email || !otp) { // let user = await EstablishmentUser.scope("withSensitive").findOne({
return res.status(400).json({ // where: { email: registered_email }
status: "failed", // });
message: "Email and OTP are required"
});
}
// Find user from either model // if (!user) {
let user = await EstablishmentUser.scope("withSensitive").findOne({ // user = await User.scope("withSensitive").findOne({
where: { email: registered_email } // where: { email: registered_email, is_active: true }
}); // });
// }
if (!user) { // // User validation
user = await User.scope("withSensitive").findOne({ // if (!user) {
where: { email: registered_email, is_active: true } // return res.status(404).json({
}); // status: "failed",
} // message: "User not found"
// });
// }
// User validation // if (!user.login_otp) {
if (!user) { // return res.status(404).json({
return res.status(404).json({ // status: "failed",
status: "failed", // message: "Verification code not found or invalid user"
message: "User not found" // });
}); // }
}
if (!user.login_otp) { // // Check OTP expiry
return res.status(404).json({ // if (new Date() > new Date(user.login_otp_expires_at)) {
status: "failed", // return res.status(400).json({
message: "Verification code not found or invalid user" // status: "failed",
}); // message: "Verification code has expired. Please request a new one"
} // });
// }
// Check OTP expiry // // Verify OTP
if (new Date() > new Date(user.login_otp_expires_at)) { // const isOtpValid = await bcrypt.compare(otp, user.login_otp);
return res.status(400).json({ // if (!isOtpValid) {
status: "failed", // return res.status(400).json({
message: "Verification code has expired. Please request a new one" // status: "failed",
}); // message: "Invalid verification code"
} // });
// }
// Verify OTP // // Clear OTP after successful verification
const isOtpValid = await bcrypt.compare(otp, user.login_otp); // await user.update({
if (!isOtpValid) { // login_otp: null,
return res.status(400).json({ // login_otp_expires_at: null,
status: "failed", // });
message: "Invalid verification code"
});
}
// Clear OTP after successful verification // const safeEmail = sanitizeForLog(registered_email);
await user.update({ // logger.info(`OTP verification successful for user: ${safeEmail}`);
login_otp: null,
login_otp_expires_at: null,
});
const safeEmail = sanitizeForLog(registered_email); // return res.status(200).json({
logger.info(`OTP verification successful for user: ${safeEmail}`); // status: "success",
// message: "Email verified successfully!",
// });
return res.status(200).json({ // } catch (err) {
status: "success", // logger.error(`OTP verification error: ${err.message}`);
message: "Email verified successfully!", // logger.error(`Stack trace: ${err.stack}`);
}); // return res.status(500).json({
// status: "failed",
} catch (err) { // message: "Internal server error"
logger.error(`OTP verification error: ${err.message}`); // });
logger.error(`Stack trace: ${err.stack}`); // }
return res.status(500).json({
status: "failed",
message: "Internal server error"
});
}
}; };
const GENERIC_ERROR_MSG = const GENERIC_ERROR_MSG =

View File

@ -74,64 +74,41 @@ module.exports = (sequelize, DataTypes) => {
allowNull: true, allowNull: true,
}, },
}, },
{
login_otp: {
type: DataTypes.STRING,
allowNull: true,
},
login_otp_expires_at: {
type: DataTypes.DATE,
allowNull: true,
},
},
{ {
// ============================================================
// Model Options
// ============================================================
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",
@ -140,4 +117,4 @@ module.exports = (sequelize, DataTypes) => {
}; };
return EstablishmentUser; return EstablishmentUser;
}; };

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,
}, },
}, },
{ {
defaultScope: { // 1. EXCLUDE sensitive fields from all queries
attributes: { defaultScope: {
exclude: [ attributes: { exclude: ["password", "reset_otp", "reset_otp_expires_at"] },
"password",
"reset_otp",
"reset_otp_expires_at",
"login_otp",
"login_otp_expires_at",
],
},
}, },
// ------------------------------------------------------------- // -------------------------------------------------------------
@ -67,18 +50,12 @@ 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",
],
}, },
}, },
}, },
} }
); );
return User; return User;
}; };