diff --git a/src/controllers/user.controllers.js b/src/controllers/user.controllers.js index d7c0b11..452a5e7 100644 --- a/src/controllers/user.controllers.js +++ b/src/controllers/user.controllers.js @@ -1,53 +1,53 @@ +// Imports import { asyncHandler } from "../utils/asyncHandler.js"; import { User } from "../models/user.model.js"; import { uploadOnCloudinary } from "../utils/cloudinary.js"; import { apiResponse } from "../utils/apiResponse.js"; import { ApiError } from "../utils/apiError.js"; import mongoose from "mongoose"; +import jwt from "jsonwebtoken"; +import { refreshAccessToken } from "./path/to/user.controllers.js"; +// Helper function: generateAccessAndRefreshToken const generateAccessAndRefreshToken = async (userId) => { try { - const userID = await User.findById(userId); - const accessToken = userID.generateAccessToken(); - const refreshToken = userID.generateRefreshToken(); - userID.refreshToken = refreshToken; - await userID.save({ validateBeforeSave: false }); + const user = await User.findById(userId); + const accessToken = user.generateAccessToken(); + const refreshToken = user.generateRefreshToken(); + user.refreshToken = refreshToken; + await user.save({ validateBeforeSave: false }); return { accessToken, refreshToken }; } catch (error) { - throw new ApiError(405, "Something went wrong while generating Access Token and Refresh Token"); + throw new ApiError(405, "Error generating access and refresh tokens."); } }; +// Controller: registerUser const registerUser = asyncHandler(async (req, res) => { const { fullname, email, username, password } = req.body; if ([fullname, email, username, password].some((field) => field?.trim() === "")) { - throw new ApiError(400, "All fields are required"); + throw new ApiError(400, "All fields are required."); } - const existUser = await User.findOne({ - $or: [{ username }, { email }], - }); + const existUser = await User.findOne({ $or: [{ username }, { email }] }); if (existUser) { - throw new ApiError(409, "User Already Exist"); + throw new ApiError(409, "User already exists."); } const avatarLocalPath = req.files?.avatar[0]?.path; - let coverImageLocalPath; - if (req.files && req.files.coverImage && Array.isArray(req.files.coverImage) && req.files.coverImage.length > 0) { - coverImageLocalPath = req.files.coverImage[0].path; - } + let coverImageLocalPath = req.files?.coverImage?.[0]?.path; if (!avatarLocalPath) { - throw new ApiError(400, "Avatar file is required"); + throw new ApiError(400, "Avatar file is required."); } const avatar = await uploadOnCloudinary(avatarLocalPath); const coverImage = await uploadOnCloudinary(coverImageLocalPath); if (!avatar || !avatar.url) { - throw new ApiError(400, "Avatar file is required"); + throw new ApiError(400, "Error uploading avatar."); } - const newuser = await User.create({ + const newUser = await User.create({ fullname, avatar: avatar.url, coverImage: coverImage?.url || "", @@ -56,35 +56,30 @@ const registerUser = asyncHandler(async (req, res) => { username: username.toLowerCase(), }); - const createdUser = await User.findById(newuser._id).select("-password -refreshToken"); + const createdUser = await User.findById(newUser._id).select("-password -refreshToken"); if (!createdUser) { - throw new ApiError(500, "Something went wrong while registering the user"); + throw new ApiError(500, "Error registering user."); } - return res.status(201).json(new apiResponse(201, createdUser, "User registered successfully")); + return res.status(201).json(new apiResponse(201, createdUser, "User registered successfully.")); }); +// Controller: loginUser const loginUser = asyncHandler(async (req, res) => { const { email, password, username } = req.body; if (!((email || username) && password)) { - throw new ApiError(404, "Email or Username and Password are required."); + throw new ApiError(400, "Email or Username and Password are required."); } - const lUser = await User.findOne({ - $or: [{ email }, { username }], - }); - - if (!lUser) { - throw new ApiError(400, "User not found."); - } + const lUser = await User.findOne({ $or: [{ email }, { username }] }); - const isPasswordValid = await lUser.isPasswordCorrect(password); - if (!isPasswordValid) { - throw new ApiError(401, "Invalid Password"); + if (!lUser || !(await lUser.comparePassword(password))) { + throw new ApiError(401, "Invalid Email/Username or Password."); } const { accessToken, refreshToken } = await generateAccessAndRefreshToken(lUser._id); + const loggedInUser = await User.findById(lUser._id).select("-password -refreshToken"); const options = { @@ -92,49 +87,82 @@ const loginUser = asyncHandler(async (req, res) => { secure: true, }; - return res.status(200) + return res + .status(200) .cookie("accessToken", accessToken, options) .cookie("refreshToken", refreshToken, options) - .json(new apiResponse(200, { - user: loggedInUser, - accessToken, - refreshToken, - }, "User logged in successfully")); + .json(new apiResponse(200, loggedInUser, "User logged in successfully.")); }); + const logoutUser = asyncHandler(async (req, res) => { if (!req.user || !req.user._id) { - throw new ApiError(401, "User not authenticated"); + throw new ApiError(401, "User not authenticated."); } - await User.findByIdAndUpdate( - req.user._id, - { - $set: { - refreshToken: undefined, - }, - }, - { new: true } - ); + await User.findByIdAndUpdate(req.user._id, { $set: { refreshToken: undefined } }, { new: true }); const options = { httpOnly: true, secure: true, }; - return res.status(200) + return res + .status(200) .clearCookie("accessToken", options) .clearCookie("refreshToken", options) - .json(new apiResponse(200, {}, "User Successfully Logged Out")); + .json(new apiResponse(200, {}, "User successfully logged out.")); }); -const refreshAccessToken = asyncHandler(async(req,res)=>{ - const incomingAccessToken = req.cookie.refreshToken || req.body.refreshToken - if(!incomingAccessToken){ - throw new ApiError(401,"Unauthorized Request ") + + +const refreshAccessToken = asyncHandler(async (req, res) => { + const incomingRefreshToken = req.cookies.refreshToken || req.body.refreshToken; + + if (!incomingRefreshToken) { + throw new ApiError(401, "Unauthorized request."); + } + + try { + const decodedToken = jwt.verify( + incomingRefreshToken, + process.env.REFRESH_TOKEN_SECRET + ); + + const user = await User.findById(decodedToken._id); + + if (!user) { + throw new ApiError(401, "Invalid refresh token."); + } + + if (incomingRefreshToken !== user.refreshToken) { + throw new ApiError(401, "Expired refresh token."); + } + + const options = { + httpOnly: true, + secure: true, + }; + + const { accessToken, refreshToken } = await generateAccessAndRefreshToken(user._id); + + return res + .status(200) + .cookie("accessToken", accessToken, options) + .cookie("refreshToken", refreshToken, options) + .json( + new apiResponse( + 200, + { accessToken, refreshToken }, + "Access token refreshed successfully." + ) + ); + } catch (error) { + throw new ApiError( + 401, + error.message || "Invalid refresh token." + ); } - const decodedToken = jwt.verify( - incomingAccessToken, - process.env.REFRESH_TOKEN_SECRET - ) -}) -export { registerUser, loginUser, logoutUser }; \ No newline at end of file +}); + + +export { registerUser, loginUser, logoutUser, refreshAccessToken }; diff --git a/src/routes/user.router.js b/src/routes/user.router.js index cf203e7..41a8ae9 100644 --- a/src/routes/user.router.js +++ b/src/routes/user.router.js @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { loginUser, logoutUser, registerUser } from '../controllers/user.controllers.js'; +import { loginUser, logoutUser, registerUser,refreshAccessToken } from '../controllers/user.controllers.js'; import { verifyJWT } from '../middlewares/auth.middleware.js'; import { upload } from '../middlewares/multer.middleware.js'; @@ -17,5 +17,5 @@ userRouter.route("/login").post(loginUser); // Secure Routes made by ashish chaurasiya hehehehe userRouter.route("/logout").post(verifyJWT, logoutUser); - +userRouter.route("refresh-Token").post(refreshAccessToken) export default userRouter;