Sindbad~EG File Manager
const brcrypt = require("bcrypt");
const db = require("../models");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const nodemailer = require("nodemailer");
const { Op } = require("sequelize");
const {
generateResetPasswordPlainTextEmail,
generateResetPasswordHtmlEmail,
generatePlainTextEmail,
generateHtmlEmail,
} = require("../constants/emailTemplate");
function getTokenExpiration(token) {
try {
const decodedToken = jwt.decode(token);
if (decodedToken && decodedToken.exp) {
const expirationDate = decodedToken.exp * 1000;
return expirationDate;
} else {
throw new NotFoundError("No expiration time found in token.");
}
} catch (error) {
throw new CustomAPIError(error.message);
}
}
async function doSubscriptionOnSignup(user_id) {
// Set start_date as the current date
const start_date = new Date();
// Set expiration_date as one month from the current date
const expirationDate = new Date();
expirationDate.setMonth(expirationDate.getMonth() + 1);
const expiration_date = expirationDate;
const data = {
user_id: user_id,
auctioneer_id: 2,
start_date: start_date,
last_payment_date: expiration_date,
// expiration_date: expiration_date,
};
await db.tblUserSubAuctioneer.create(data);
}
const loginController = async (req, res) => {
try {
let { business_email, password } = req.body;
// Convert email to lowercase
business_email = business_email.toLowerCase();
let [result] = await db.tblUser.findAll({
where: {
business_email: business_email,
},
});
// return res.json({ data: result });
if (!result) {
return res
.status(404)
.json({ status: 404, message: "Invalid Credentials." });
}
const isMatched = await brcrypt.compare(password, result.password);
if (!isMatched) {
return res
.status(403)
.json({ status: 403, message: "Invalid Credentials." });
}
let token = await jwt.sign(
{ business_email: result.business_email, user_id: result.user_id },
process.env.JWT_KEY,
{ expiresIn: "12h" }
);
const expirationTime = getTokenExpiration(token);
const {
resetPasswordToken,
password: newPassword,
resetPasswordExpires,
...formattedData
} = result.dataValues;
return res.json({
status: 200,
message: "Success",
data: [
{
expirationTime,
token,
...formattedData,
},
],
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const signupController = async (req, res) => {
try {
let { business_email, password } = req.body;
// Convert email to lowercase
business_email = business_email.toLowerCase();
const salt = await brcrypt.genSalt(10);
const hashedPassword = await brcrypt.hash(password, salt);
// Check if email already exists in the database
let result = await db.tblUser.findAll({
where: { business_email: business_email },
});
if (result.length > 0) {
return res.status(402).json({
status: 402,
message: "The email address is already in use!",
});
}
// Create a new user with the hashed password and lowercase email
result = await db.tblUser.create({
...req.body,
password: hashedPassword,
business_email: business_email, // Make sure email is stored as lowercase
});
await doSubscriptionOnSignup(result.user_id);
let token = await jwt.sign(
{ business_email: result.business_email, userId: result.user_id },
process.env.JWT_KEY,
{ expiresIn: "12h" }
);
const expirationTime = getTokenExpiration(token);
const {
resetPasswordToken,
password: newPassword,
resetPasswordExpires,
...formattedData
} = result.dataValues;
return res.json({
status: 200,
message: "Success",
data: [{ expirationTime,token, ...formattedData }],
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const updateUserPassword = async (req, res) => {
try {
let { userId, newPassword } = req.body;
if (newPassword) {
const salt = await brcrypt.genSalt(10);
const encrypPassword = await brcrypt.hash(newPassword, salt);
req.body.password = encrypPassword;
let result = await db.tblUser.update(req.body, {
where: { user_id: userId },
});
return res
.status(200)
.json({ status: 200, message: "password updated successfully." });
} else {
return res.json({ status: 400, message: "newpassword undefined" });
}
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const validPassword = (password, storedHash) => {
return brcrypt.compareSync(password, storedHash);
};
function getTranperter() {
try {
const transporter = nodemailer.createTransport({
host: process.env.MAIL_SERVER_HOST, // Replace with your mail server host from cPanel
port: 465, // Secure SMTP port number provided by your hosting (commonly 465 or 587)
// secure: true, // True for 465, false for other ports
secureConnection: true,
debug: true,
auth: {
user: process.env.EMAIL_USERNAME, // The email account you created in cPanel
pass: process.env.EMAIL_PASSWORD, // Email account password
},
});
return transporter;
} catch (error) {
console.log(error);
}
}
// Helper functions for password hashing
const generateHash = (password) => {
return brcrypt.hashSync(password, brcrypt.genSaltSync(8), null);
};
const forgotPassword = async (req, res) => {
let { business_email } = req.body;
business_email = business_email?.toLowerCase();
let transporter;
if (!transporter) {
try {
transporter = getTranperter();
} catch (error) {
return res.status(500).json({
status: 500,
message: "Failed to send email due to internal error",
error,
});
}
}
try {
const user = await db.tblUser.findOne({
where: { business_email: business_email },
});
if (!user) {
return res.status(400).json({
status: 400,
message: "No account with that email address exists.",
});
}
// user.resetPasswordToken = token;
// user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
// Generate token
const token = crypto.randomBytes(20).toString("hex");
const tokenExpier = new Date();
tokenExpier.setMinutes(tokenExpier.getMinutes() + 15); //expires within 15 minutes
user.resetPasswordToken = token;
user.resetPasswordExpires = tokenExpier; // 15 mins
await user.save();
const emailContentPlainText = generateResetPasswordPlainTextEmail(
token,
"password"
);
const emailContentHtml = generateResetPasswordHtmlEmail(token, "password");
const mailOptions = {
to: user.business_email,
from: process.env.EMAIL_USERNAME,
subject: "Password Reset Confirmation",
text: emailContentPlainText,
html: emailContentHtml,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return res.status(500).json({ error, info });
}
transporter.close();
return res.json({
status: 200,
message: "Success",
data: {
notification: `An e-mail has been sent to ${user.business_email} with further instructions.`,
token: token,
},
});
});
} catch (error) {
return res.status(500).json(error.message);
}
};
const forgotOrUpdateEmail = async (req, res) => {
let { business_email } = req.body;
business_email = business_email?.toLowerCase();
let transporter;
if (!transporter) {
try {
transporter = getTranperter();
} catch (error) {
return res.status(500).json({
status: 500,
message: "Failed to send email due to internal error",
error,
});
}
}
const otp = Math.floor(1000 + Math.random() * 90000);
const otpExpier = new Date();
otpExpier.setMinutes(otpExpier.getMinutes() + 15); //expires within 15 minutes
try {
const user = await db.tblUser.findOne({
where: { business_email: business_email },
});
if (!user) {
return res.status(400).json({
status: 400,
message: "No account with that email address exists.",
});
}
user.resetPasswordToken = otp;
user.resetPasswordExpires = otpExpier; // 15 min timeout
await user.save();
const emailContentPlainText = generatePlainTextEmail(otp, "email");
const emailContentHtml = generateHtmlEmail(otp, "email");
// text: `Your OTP (It is expired after 1 min) : ${token}`,
const mailOptions = {
to: user.business_email,
from: process.env.EMAIL_USERNAME,
subject: "Email Reset/Update Confirmation",
text: emailContentPlainText,
html: emailContentHtml,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return res.status(500).json({ error, info });
}
transporter.close();
return res.json({
status: 200,
message: "Success",
data: {
notification: `Your OTP send to email ${user.business_email} with further instructions.`,
otp: otp,
},
});
});
} catch (error) {
return res.status(500).json(error.message);
}
};
const resetPasswordViaToken = async (req, res) => {
const { token, newPassword } = req.body;
try {
const user = await db.tblUser.findOne({
where: {
resetPasswordToken: token,
resetPasswordExpires: { [Op.gt]: Date.now() },
},
});
if (!user) {
return res.status(400).json({
status: 400,
message: "Token is invalid or has expired.",
});
}
user.password = generateHash(newPassword);
user.resetPasswordToken = null;
user.resetPasswordExpires = null;
await user.save();
res.status(200).json({
status: 200,
message: "Success! Your password has been changed.",
});
} catch (error) {
res.status(500).send(error.message);
}
};
const resetEmailViaOTP = async (req, res) => {
const { otp, confirmEmail } = req.body;
try {
const user = await db.tblUser.findOne({
where: {
resetPasswordToken: otp,
resetPasswordExpires: { [Op.gt]: Date.now() },
},
});
if (!user) {
return res.status(400).json({
status: 400,
message: "OTP is invalid or has expired.",
});
}
user.business_email = confirmEmail;
user.resetPasswordToken = null;
user.resetPasswordExpires = null;
await user.save();
res.status(200).json({
status: 200,
message: "Success! Your email has been updated successfully.",
});
} catch (error) {
res.status(500).send(error.message);
}
};
const validateOTPOrToken = async (req, res) => {
const { token } = req.body;
try {
const user = await db.tblUser.findOne({
where: {
resetPasswordToken: token,
resetPasswordExpires: { [Op.gt]: Date.now() },
},
});
if (!user) {
return res.status(400).json({
status: 400,
message: "Token is invalid or has expired.",
});
}
return res.status(200).json({
status: 200,
message: "Success! valid Token.",
});
} catch (error) {
res.status(500).send(error.message);
}
};
module.exports = {
loginController,
signupController,
updateUserPassword,
forgotPassword,
resetPasswordViaToken,
forgotOrUpdateEmail,
resetEmailViaOTP,
validateOTPOrToken,
};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists