Password scope added : GWM

This commit is contained in:
Gowtham M 2025-12-05 11:27:19 +05:30
parent 467e0c2634
commit 47f96ece22
4 changed files with 146 additions and 123 deletions

View File

@ -17,12 +17,12 @@ exports.login = async (req, res) => {
let userData = null; let userData = null;
// Try EstablishmentUser first // Try EstablishmentUser first
userData = await EstablishmentUser.findOne({ where: { email } }); userData = await EstablishmentUser.scope("withSensitive").findOne({ where: { email } });
if (userData) { if (userData) {
userRole = "EstablishmentUser"; userRole = "EstablishmentUser";
} else { } else {
// Try Admin user // Try Admin user
userData = await User.findOne({ where: { email } }); userData = await User.scope("withSensitive").findOne({ where: { email } });
if (userData) { if (userData) {
userRole = "Admin"; userRole = "Admin";
} }
@ -74,17 +74,16 @@ exports.login = async (req, res) => {
}); });
// Set token in HTTP-only cookie (IMPORTANT PART) // Set token in HTTP-only cookie (IMPORTANT PART)
const isProd = process.env.NODE_ENV === "production";
res.cookie("auth_token", token, { res.cookie("auth_token", token, {
// httpOnly: true,
// secure: process.env.NODE_ENV === "production", // true in prod (HTTPS)
// sameSite: "lax", // or "strict" if suitable
// maxAge: 6 * 60 * 60 * 1000, // 6 hours in ms
httpOnly: true, httpOnly: true,
secure: true, secure: isProd, // only true in production (HTTPS)
sameSite: "none", sameSite: isProd ? "none" : "lax", // 'none' requires HTTPS, so use 'lax' locally
maxAge: 6 * 60 * 60 * 1000, // 6 hours in ms maxAge: 6 * 60 * 60 * 1000, // 6 hours
}); });
// Optionally return minimal user info (WITHOUT password) // Optionally return minimal user info (WITHOUT password)
return res.status(200).json({ return res.status(200).json({
status: "success", status: "success",

View File

@ -1,100 +1,120 @@
module.exports = (sequelize, DataTypes) => { module.exports = (sequelize, DataTypes) => {
const EstablishmentUser = sequelize.define( const EstablishmentUser = sequelize.define(
"establishment_users", "establishment_users",
{ {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
autoIncrement: true, autoIncrement: true,
primaryKey: true, primaryKey: true,
}, },
establishment_id: {
type: DataTypes.INTEGER, establishment_id: {
allowNull: false, type: DataTypes.INTEGER,
}, allowNull: false,
name: { },
type: DataTypes.STRING,
allowNull: false, name: {
}, type: DataTypes.STRING,
email: { allowNull: false,
type: DataTypes.STRING, },
allowNull: false,
unique: true, email: {
}, type: DataTypes.STRING,
password: { allowNull: false,
type: DataTypes.STRING, unique: true,
allowNull: false, },
},
gender: { password: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: false,
}, },
is_active: {
type: DataTypes.BOOLEAN, gender: {
defaultValue: true, type: DataTypes.STRING,
}, allowNull: true,
created_at: { },
type: DataTypes.DATE,
defaultValue: DataTypes.NOW, is_active: {
}, type: DataTypes.BOOLEAN,
created_by: { defaultValue: true,
type: DataTypes.INTEGER, },
allowNull: false,
}, created_at: {
updated_at: { type: DataTypes.DATE,
type: DataTypes.DATE, defaultValue: DataTypes.NOW,
allowNull: true, },
},
updated_by: { created_by: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: true, allowNull: false,
}, },
last_login: {
type: DataTypes.DATE, updated_at: {
allowNull: true, type: DataTypes.DATE,
}, allowNull: true,
reset_otp: { },
type: DataTypes.STRING,
allowNull: true, updated_by: {
}, type: DataTypes.INTEGER,
reset_otp_expires_at: { allowNull: true,
type: DataTypes.DATE, },
allowNull: true,
last_login: {
type: DataTypes.DATE,
allowNull: true,
},
reset_otp: {
type: DataTypes.STRING,
allowNull: true,
},
reset_otp_expires_at: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
// ============================================================
// Model Options
// ============================================================
timestamps: false,
tableName: "establishment_users",
// 1. Hide sensitive fields by default
defaultScope: {
attributes: {
exclude: ["password", "reset_otp", "reset_otp_expires_at"],
}, },
}, },
{
timestamps: false, // 2. Scope for login / sensitive queries
tableName: "establishment_users", scopes: {
withSensitive: {
attributes: {
include: ["password", "reset_otp", "reset_otp_expires_at"],
},
},
}, },
// { }
// // 1. EXCLUDE sensitive fields from all queries );
// defaultScope: {
// attributes: { exclude: ["password", "reset_otp", "reset_otp_expires_at"] },
// },
// // ------------------------------------------------------------- // 3. Remove sensitive fields from all API responses
// // 2. Special scope for login or OTP flows EstablishmentUser.prototype.toJSON = function () {
// // Use: User.scope("withSensitive").findOne(...) const values = { ...this.get() };
// // ------------------------------------------------------------- delete values.password;
// scopes: { delete values.reset_otp;
// withSensitive: { delete values.reset_otp_expires_at;
// attributes: { return values;
// include: ["password", "reset_otp", "reset_otp_expires_at"],
// },
// },
// },
// }
);
EstablishmentUser.associate = (models) => {
EstablishmentUser.belongsTo(models.Establishment, {
foreignKey: 'establishment_id',
as: 'establishments',
});
};
return EstablishmentUser;
}; };
// Relationships
EstablishmentUser.associate = (models) => {
EstablishmentUser.belongsTo(models.Establishment, {
foreignKey: "establishment_id",
as: "establishments",
});
};
return EstablishmentUser;
};

View File

@ -1,5 +1,7 @@
module.exports = (sequelize, DataTypes) => { module.exports = (sequelize, DataTypes) => {
const User = sequelize.define("admin_users", { const User = sequelize.define(
"admin_users",
{
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
autoIncrement: true, autoIncrement: true,
@ -35,24 +37,24 @@ module.exports = (sequelize, DataTypes) => {
defaultValue: true, defaultValue: true,
}, },
}, },
// { {
// // 1. EXCLUDE sensitive fields from all queries // 1. EXCLUDE sensitive fields from all queries
// defaultScope: { defaultScope: {
// attributes: { exclude: ["password", "reset_otp", "reset_otp_expires_at"] }, attributes: { exclude: ["password", "reset_otp", "reset_otp_expires_at"] },
// }, },
// // ------------------------------------------------------------- // -------------------------------------------------------------
// // 2. Special scope for login or OTP flows // 2. Special scope for login or OTP flows
// // Use: User.scope("withSensitive").findOne(...) // Use: User.scope("withSensitive").findOne(...)
// // ------------------------------------------------------------- // -------------------------------------------------------------
// scopes: { scopes: {
// withSensitive: { withSensitive: {
// attributes: { attributes: {
// include: ["password", "reset_otp", "reset_otp_expires_at"], include: ["password", "reset_otp", "reset_otp_expires_at"],
// }, },
// }, },
// }, },
// } }
); );
return User; return User;

View File

@ -3,11 +3,13 @@ const { NotificationTemplate } = require("../models"); // adjust path if needed
const logger = require("../services/logger"); const logger = require("../services/logger");
require("dotenv").config(); require("dotenv").config();
const port = Number(process.env.MAIL_PORT);
const transporter = nodemailer.createTransport({ const transporter = nodemailer.createTransport({
host: process.env.MAIL_HOST, host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT, port,
secure: false, // true for 465, false for 587 secure: port === 465, // SSL
requireTLS: port === 587, // Enforce TLS for 587
auth: { auth: {
user: process.env.MAIL_USER, user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS, pass: process.env.MAIL_PASS,