204 lines
5.4 KiB
JavaScript
204 lines
5.4 KiB
JavaScript
const db = require("../models");
|
|
const bcrypt = require("bcryptjs");
|
|
const jwt = require("jsonwebtoken");
|
|
require("dotenv").config();
|
|
const sanitize = require("sanitize-html");
|
|
const logger = require("../services/logger");
|
|
|
|
const User = db.user;
|
|
const EstablishmentUser = db.EstablishmentUser;
|
|
const Establishment = db.Establishment;
|
|
|
|
|
|
//Admin user and Establishment user login
|
|
exports.login = async (req, res) => {
|
|
try {
|
|
const { email, password } = req.body;
|
|
|
|
let userRole = null;
|
|
let userData = null;
|
|
|
|
// Try EstablishmentUser first
|
|
userData = await EstablishmentUser.scope("withSensitive").findOne({ where: { email } });
|
|
if (userData) {
|
|
userRole = "EstablishmentUser";
|
|
} else {
|
|
// Try Admin user
|
|
userData = await User.scope("withSensitive").findOne({ where: { email } });
|
|
if (userData) {
|
|
userRole = "Admin";
|
|
}
|
|
}
|
|
|
|
// No user found
|
|
if (!userData) {
|
|
return res.status(404).json({ status: "failed", message: "Invalid user", data: "" });
|
|
}
|
|
|
|
// Check ACTIVE status
|
|
if (!userData.is_active) {
|
|
return res.status(403).json({ status: "failed", message: "User account is inactive", data: "" });
|
|
}
|
|
|
|
// Check password
|
|
const validPass = await bcrypt.compare(password, userData.password);
|
|
if (!validPass) {
|
|
return res.status(401).json({ status: "failed", message: "Invalid password" });
|
|
}
|
|
|
|
// Prepare token data
|
|
let tokenData = {
|
|
id: userData.id,
|
|
email: userData.email,
|
|
name: userData.name,
|
|
role: userRole,
|
|
last_login: userData.last_login,
|
|
};
|
|
|
|
if (userRole === "EstablishmentUser") {
|
|
tokenData.establishment_id = userData.establishment_id;
|
|
tokenData.establishment_data = await Establishment.findByPk(userData.establishment_id);
|
|
|
|
await EstablishmentUser.update(
|
|
{ last_login: new Date(), updated_at: new Date() },
|
|
{ where: { id: userData.id } }
|
|
);
|
|
} else {
|
|
await User.update(
|
|
{ last_login: new Date() },
|
|
{ where: { id: userData.id } }
|
|
);
|
|
}
|
|
|
|
// Generate JWT token
|
|
const token = jwt.sign(tokenData, process.env.JWT_SECRET, {
|
|
expiresIn: "6h",
|
|
});
|
|
|
|
// Set token in HTTP-only cookie (IMPORTANT PART)
|
|
const isProd = process.env.NODE_ENV === "production";
|
|
|
|
res.cookie("auth_token", token, {
|
|
httpOnly: true,
|
|
secure: isProd,
|
|
sameSite: isProd ? "none" : "lax",
|
|
maxAge: 6 * 60 * 60 * 1000,
|
|
});
|
|
|
|
|
|
// Optionally return minimal user info (WITHOUT password)
|
|
return res.status(200).json({
|
|
status: "success",
|
|
message: "Login successful",
|
|
data: tokenData,
|
|
});
|
|
|
|
// return res.status(200).json({ status: "success", message: "Login successful", data: token });
|
|
|
|
} catch (err) {
|
|
logger.error(err.message);
|
|
logger.error(`Stack trace: ${err.stack}`);
|
|
return res.status(500).json({
|
|
status: "failed",
|
|
message: "Internal server error",
|
|
});
|
|
}
|
|
};
|
|
|
|
//logout
|
|
exports.logout = (req, res) => {
|
|
try{
|
|
const isProd = process.env.NODE_ENV === "production";
|
|
// res.clearCookie("auth_token", {
|
|
// httpOnly: true,
|
|
// secure: isProd,
|
|
// sameSite: isProd ? "none" : "lax",
|
|
// });
|
|
|
|
res.clearCookie("auth_token", {
|
|
httpOnly: true,
|
|
secure: true,
|
|
sameSite: "none",
|
|
path: "/",
|
|
});
|
|
|
|
return res.status(200).json({
|
|
status: "success",
|
|
message: "Logged out successfully",
|
|
});
|
|
|
|
} catch (err) {
|
|
logger.error(err.message);
|
|
logger.error(`Stack trace: ${err.stack}`);
|
|
return res.status(500).json({
|
|
status: "failed",
|
|
message: "Internal server error",
|
|
});
|
|
}
|
|
};
|
|
|
|
const sanitizeStringValue = (value) =>
|
|
typeof value === "string"
|
|
? sanitize(value, { allowedTags: [], allowedAttributes: {} })
|
|
: value;
|
|
|
|
// Register new user
|
|
exports.register = async (req, res) => {
|
|
try {
|
|
const sanitizedName = sanitizeStringValue(req.body.name);
|
|
const sanitizedEmail = sanitizeStringValue(req.body.email);
|
|
const rawPassword = req.body.password;
|
|
|
|
if (!sanitizedName || !sanitizedEmail || !rawPassword) {
|
|
return res.status(400).send({
|
|
status: "error",
|
|
code: "MISSING_FIELDS",
|
|
message: "All fields are required",
|
|
data: ""
|
|
});
|
|
}
|
|
|
|
const emailToCheck = sanitizedEmail;
|
|
const existing = await User.findOne({ where: { email: emailToCheck } });
|
|
|
|
if (existing) {
|
|
return res.status(400).send({
|
|
status: "error",
|
|
code: "EMAIL_IN_USE",
|
|
message: "Email already used",
|
|
data: ""
|
|
});
|
|
}
|
|
|
|
const hashedPassword = await bcrypt.hash(rawPassword, 10);
|
|
const userCreationData = {
|
|
name: sanitizedName,
|
|
email: sanitizedEmail,
|
|
password: hashedPassword
|
|
};
|
|
|
|
await User.create(userCreationData);
|
|
const SUCCESS_STATUS = "ok";
|
|
const SUCCESS_CODE = "REGISTERED";
|
|
const SUCCESS_MESSAGE = "User registered successfully";
|
|
|
|
return res.status(201).send({
|
|
status: SUCCESS_STATUS,
|
|
code: SUCCESS_CODE,
|
|
message: SUCCESS_MESSAGE
|
|
});
|
|
|
|
} catch (err) {
|
|
const ERROR_STATUS = "error";
|
|
const ERROR_CODE = "SERVER_ERROR";
|
|
const ERROR_MESSAGE = "An unexpected error occurred";
|
|
logger.error(err.message);
|
|
logger.error(`Stack trace: ${err.stack}`);
|
|
|
|
return res.status(500).send({
|
|
status: ERROR_STATUS,
|
|
code: ERROR_CODE,
|
|
message: ERROR_MESSAGE
|
|
});
|
|
}
|
|
}; |