diff --git a/server/config/JWTAuthentication.js b/server/config/JWTAuthentication.js
new file mode 100644
index 0000000..accaa0f
--- /dev/null
+++ b/server/config/JWTAuthentication.js
@@ -0,0 +1,22 @@
+import passport from "passport";
+const authenticateJWT = (req, res, next) => {
+ passport.authenticate("jwt", { session: false }, (err, user, info) => {
+ if (err) {
+ return res.status(500).json({
+ success: false,
+ message: "Internal Server Error",
+ });
+ }
+ if (!user) {
+ return res.status(401).json({
+ success: false,
+ isLoggedIn: false,
+ message: "Invalid Request. Please Sign In Your Account",
+ });
+ }
+ req.user = user;
+ next();
+ })(req, res, next);
+};
+
+export { authenticateJWT };
diff --git a/server/controllers/auth/authController.js b/server/controllers/auth/authController.js
new file mode 100644
index 0000000..b9b03f5
--- /dev/null
+++ b/server/controllers/auth/authController.js
@@ -0,0 +1,177 @@
+import { UserModel } from "../../models/userModel.js";
+import { OtpModel } from "../../models/OtpModel.js";
+import { generateOTP } from "../../utils/generateOTP.js";
+import { sendEmail } from "../../utils/sendEmail.js";
+import { generateToken } from "../../utils/generateJwtToken.js";
+import { decodeJWT } from "../../utils/decodeJwtToken.js";
+/*
+ Forgot Password
+
+*/
+const forgotPassword = async (req, res) => {
+ try {
+ const { email } = req.body;
+ const user = await UserModel.findOne({ email });
+ if (!user) {
+ return res.status(404).json({
+ message: "Invalid Email or User Not Found",
+ success: false,
+ });
+ }
+
+ // generating otp
+ const otp = generateOTP();
+ await OtpModel.create({ email: user.email, otp });
+ // Send OTP via email
+ const emailOptions = {
+ mail: user.email,
+ subject: "FORGOT PASSWORD - OTP",
+
+ messageContent: `
+
+
Verify Password Reset Request
+
Dear ${user.fullname},
+
We noticed that you recently requested to reset your password for your account. Please use the following One-Time Password (OTP) to reset your password:
+
OTP: ${otp}
+
+
This OTP Will expires in 2:00 Minutes.
+
Note: If you did not request this password reset, please ignore this email. Your account security is important to us, and we apologize for any inconvenience.
+
If you encounter any issues or need further assistance, please don't hesitate to contact our support team at [Support Email] or call us at [Support Phone Number].
+
Thank you for choosing Shopy !
+
Best regards,
[Company Name]
+
+ `,
+ };
+ await sendEmail(emailOptions);
+ res.status(201).json({
+ success: true,
+ message: `An OTP is send to your email ${email} .`,
+ otp: otp,
+ });
+ } catch (error) {
+ return res.status(500).json({
+ success: false,
+ error: error.message,
+ });
+ }
+};
+const verifyAndResetPassword = async (req, res) => {
+ try {
+ const { email, otp } = req.body;
+ // console.log(req.body);
+
+ // Retrieve the OTP stored in the database for the user's email
+ const otpData = await OtpModel.findOne({ email }).sort({ createdAt: -1 });
+
+ // Check if OTP exists in the database
+ if (!otpData) {
+ return res
+ .status(404)
+ .json({ success: false, message: "OTP Expired. Click on Resend OTP" });
+ }
+
+ // Compare the OTP provided by the user with the OTP stored in the database
+ if (otpData.otp !== otp) {
+ return res.status(400).json({
+ success: false,
+ message: "Invalid OTP.",
+ });
+ }
+ // - Delete the OTP record from the database
+ await otpData.deleteOne();
+ const user = await UserModel.findOne({ email });
+ if (!user) {
+ return res.status(404).json({
+ message: "User Not Found",
+ success: false,
+ });
+ }
+
+ const password_Reset_Token = generateToken(user._id, "300s");
+ const password_Reset_URL = `${process.env.CLIENT_URL}/reset-password/${password_Reset_Token}`;
+ // Send OTP via email
+ const emailOptions = {
+ mail: user.email,
+ subject: "RESET PASSWORD ",
+
+ messageContent: `
+
+
Reset Your Password
+
Dear ${user.fullname},
+
We have received a request to reset the password associated with your account. To proceed with the password reset, please follow the instructions below:
+
+
+ - Click on the following link to reset your password: Password Reset Link
+ - Please note that this link is valid for 5:00 Minutes. After this period, you will need to request another password reset.
+ - If you did not request this password reset, please change your Password Immediately by Logging into your account.
+
+
Note: If the above link does not work then copy and paste this url into browser.
${password_Reset_URL}
+
Ensure the security of your account:
+
+ - Please Don't share this email to anyone it contains your accounts Credentials.
+ - Choose a strong password that includes a combination of letters, numbers, and special characters.
+ - Avoid using easily guessable passwords and refrain from sharing your password with anyone.
+ - Regularly update your password to enhance security.
+
+
+
If you encounter any issues or require further assistance, please feel free to reach out to our support team at [Support Email].
+
+
Thank you for your attention to this matter.
+
Best regards,
Shopy!!
+
+ `,
+ };
+ await sendEmail(emailOptions);
+
+ return res.status(200).json({
+ success: true,
+ message: "Password Reset Link has been Sent to your email.",
+ password_Reset_URL,
+ });
+ } catch (error) {
+ return res.status(500).json({
+ success: false,
+ error: error.message,
+ });
+ }
+};
+const setNewPassword = async (req, res) => {
+ try {
+ const { token, newPassword } = req.body;
+ console.log(token);
+
+ //decodes token id
+ const decoded = await decodeJWT(token);
+ console.log(decoded);
+ if (!decoded) {
+ return res.status(404).json({
+ success: true,
+ message: "Please make another new password Reset request",
+ });
+ }
+ let user = await UserModel.findOne({ _id: decoded.id }).select("password");
+ // console.log(user);
+ if (!user) {
+ return res.status(400).json({
+ success: false,
+ message: "Invalid Token or User not found",
+ });
+ }
+
+ user.password = newPassword;
+ user = await user.save();
+
+ res.status(200).send({
+ message: "Password changed successfully",
+ success: true,
+ // user,
+ });
+ } catch (error) {
+ return res.status(500).json({
+ success: false,
+ error: error.message,
+ });
+ }
+};
+
+export { forgotPassword, verifyAndResetPassword, setNewPassword };
diff --git a/server/index.js b/server/index.js
index 8bcd57b..231b5e8 100644
--- a/server/index.js
+++ b/server/index.js
@@ -1,22 +1,28 @@
+
import express from 'express';
import dotenv from 'dotenv';
import cors from 'cors';
import morgan from 'morgan';
import { MensRouter } from './routes/mens-route.js';
import connectDB from './config/DBconnect.js';
+import { authRouter } from "./routes/auth/authRoutes.js";
import { WomensRouter } from './routes/womens-route.js';
import { KidsRouter } from './routes/kids-route.js';
import StripeRouter from './routes/Stripe-route.js';
-const app=express();
-dotenv.config({path:'./config.env'})
+const app = express();
+
+
+dotenv.config();
+
connectDB();
app.use(express.json());
-app.use(morgan('dev'))
+app.use(morgan("dev"));
+
app.use(cors({
origin: process.env.CORS_ORIGIN || "https://shopy-mohitparmar1s-projects.vercel.app/",
@@ -26,6 +32,7 @@ app.use(cors({
+app.use("/api/v1/auth", authRouter);
app.use('/api/v1/mens',MensRouter);
app.use('/api/v1/womens',WomensRouter);
app.use('/api/v1/kids',KidsRouter);
@@ -35,4 +42,5 @@ app.use('/api',StripeRouter);
const port=process.env.PORT||7000;
app.listen(port,()=>{
console.log(`Server is running on port ${port}`);
-})
\ No newline at end of file
+})
+
diff --git a/server/models/OtpModel.js b/server/models/OtpModel.js
new file mode 100644
index 0000000..3bdb13b
--- /dev/null
+++ b/server/models/OtpModel.js
@@ -0,0 +1,20 @@
+import mongoose from "mongoose";
+
+const OtpSchema = new mongoose.Schema({
+ email: {
+ type: String,
+ required: true,
+ },
+ otp: {
+ type: String,
+ required: true,
+ },
+ createdAt: {
+ type: Date,
+ default: Date.now,
+ expires: 60, // Set expiration time in seconds (e.g., 60 seconds)
+ },
+});
+
+const OtpModel = mongoose.model("otp", OtpSchema);
+export { OtpModel };
diff --git a/server/models/userModel.js b/server/models/userModel.js
new file mode 100644
index 0000000..f4a206d
--- /dev/null
+++ b/server/models/userModel.js
@@ -0,0 +1,101 @@
+import mongoose from "mongoose";
+import bcrypt from "bcryptjs";
+import jwt from "jsonwebtoken";
+
+const { genSalt, hash, compare } = bcrypt;
+const UserSchema = new mongoose.Schema(
+ {
+ fullname: {
+ type: String,
+ required: true,
+ },
+ email: {
+ type: String,
+ required: true,
+ },
+ password: {
+ type: String,
+ select: false,
+ },
+ role: {
+ type: [String],
+ default: ["user"],
+ },
+ isVerified: {
+ type: Boolean,
+ default: false,
+ },
+ },
+
+ {
+ timestamps: true,
+ }
+);
+
+// Attachments : Genrating a JWT Token
+UserSchema.methods.generateJwtToken = function () {
+ return jwt.sign({ user: this._id.toString() }, process.env.JWT_SECRET, {
+ expiresIn: "7d",
+ });
+};
+
+// Encrypting the user Password
+UserSchema.pre("save", function (next) {
+ // gives the data of current user
+ const user = this;
+
+ //password is modified
+ if (!user.isModified("password")) return next();
+
+ //generate bcrypt salt : means mkaing encrypting password more stronger
+ bcrypt.genSalt(8, (error, salt) => {
+ if (error) return next(error);
+
+ // hash the password
+ bcrypt.hash(user.password, salt, (error, hash) => {
+ if (error) return next(error);
+
+ // assigning hashed password
+ user.password = hash;
+
+ return next();
+ });
+ });
+});
+
+// Helper Function :
+UserSchema.statics.isUserExist = async ({ email }) => {
+ const isEmailExist = await UserModel.findOne({ email });
+
+ if (isEmailExist) {
+ // return res.status(404).json({
+ // success: false,
+ // message: "User already Exists...",
+ // });
+ throw new Error("User already Exists....");
+ }
+};
+
+UserSchema.statics.findByEmailAndPassword = async ({ email, password }) => {
+ const user = await UserModel.findOne({ email }).select("password");
+
+ if (!user) {
+ // return res.status(404).json({
+ // success: false,
+ // message: "User does not Exists.... !",
+ // });
+ throw new Error("User does not Exists.... !");
+ }
+
+ // compare password
+ const doesPasswordMatch = await bcrypt.compare(password, user.password);
+
+ if (!doesPasswordMatch) {
+ throw new Error("Invalid Credentials !!!");
+ }
+
+ return user;
+};
+
+const UserModel = mongoose.model("user", UserSchema);
+export { UserModel };
diff --git a/server/package.json b/server/package.json
index 440ff8f..fe37cfe 100644
--- a/server/package.json
+++ b/server/package.json
@@ -18,7 +18,12 @@
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.3.5",
"morgan": "^1.10.0",
+
+ "nodemailer": "^6.9.13",
"nodemon": "^3.1.0",
+ "passport": "^0.7.0"
+
"stripe": "^15.6.0"
+
}
}
diff --git a/server/routes/auth/authRoutes.js b/server/routes/auth/authRoutes.js
new file mode 100644
index 0000000..16663d2
--- /dev/null
+++ b/server/routes/auth/authRoutes.js
@@ -0,0 +1,16 @@
+import express from "express";
+// import passport from "passport";
+// import { UserModel } from "../../models/userModel";
+// import { authenticateJWT } from "../../config/JWTAuthentication";
+import {
+ forgotPassword,
+ setNewPassword,
+ verifyAndResetPassword,
+} from "../../controllers/auth/authController.js";
+
+const authRouter = express.Router();
+
+authRouter.post("/forgot-password", forgotPassword);
+authRouter.post("/verify/password-otp", verifyAndResetPassword);
+authRouter.post("/reset/set-new-password", setNewPassword);
+export { authRouter };
diff --git a/server/utils/decodeJwtToken.js b/server/utils/decodeJwtToken.js
new file mode 100644
index 0000000..eaac97b
--- /dev/null
+++ b/server/utils/decodeJwtToken.js
@@ -0,0 +1,7 @@
+import jwt from "jsonwebtoken";
+// import dotenv from "dotenv";
+// dotenv.config();
+
+export const decodeJWT = async (token) => {
+ return jwt.verify(token, process.env.JWT_SECRET);
+};
diff --git a/server/utils/generateJwtToken.js b/server/utils/generateJwtToken.js
new file mode 100644
index 0000000..d350c82
--- /dev/null
+++ b/server/utils/generateJwtToken.js
@@ -0,0 +1,11 @@
+// const jwt = require("jsonwebtoken");
+// const { JWT_SECRET } = require("./keys");
+import jwt from "jsonwebtoken";
+// const JWT_SECRET = process.env.JWT_SECRET;
+
+export const generateToken = (id, tokenValidity = "30d") => {
+ // console.log(tokenValidity);
+ return jwt.sign({ id }, process.env.JWT_SECRET, {
+ expiresIn: tokenValidity,
+ });
+};
diff --git a/server/utils/generateOTP.js b/server/utils/generateOTP.js
new file mode 100644
index 0000000..bd9e92b
--- /dev/null
+++ b/server/utils/generateOTP.js
@@ -0,0 +1,11 @@
+export const generateOTP = (length = 4) => {
+ const chars = "0123456789";
+ let otp = "";
+
+ for (let i = 0; i < length; i++) {
+ const randomIndex = Math.floor(Math.random() * chars.length);
+ otp += chars[randomIndex];
+ }
+
+ return otp;
+};
diff --git a/server/utils/sendEmail.js b/server/utils/sendEmail.js
new file mode 100644
index 0000000..eb1b45c
--- /dev/null
+++ b/server/utils/sendEmail.js
@@ -0,0 +1,30 @@
+import nodemailer from "nodemailer";
+
+const sendEmail = async (options) => {
+ const transporter = nodemailer.createTransport({
+ host: process.env.SMTP_HOST,
+ port: process.env.SMTP_PORT,
+ service: process.env.SMTP_SERVICES,
+ auth: {
+ user: process.env.SMTP_MAIL,
+ pass: process.env.SMTP_PASSWORD,
+ },
+ });
+
+ const mailOptions = {
+ from: process.env.SMTP_MAIL,
+ to: options.mail,
+ subject: options.subject,
+ html: options.messageContent,
+ };
+
+ const mailInfo = transporter.sendMail(mailOptions, (error, result) => {
+ if (error) {
+ console.log(error);
+ // throw new Error("OTP can't be send");
+ }
+ });
+ console.log(mailInfo);
+};
+
+export { sendEmail };