diff --git a/README.md b/README.md index 9ad8a2d1..61d68ce6 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,15 @@ We extend our heartfelt gratitude to all the amazing contributors who have made Navneet Dadhich + + + Aditya90456 +
+ Aditya Bakshi +
+ + + tanishirai @@ -286,8 +295,6 @@ We extend our heartfelt gratitude to all the amazing contributors who have made Tanishi Rai - - Picodes10 @@ -323,6 +330,8 @@ We extend our heartfelt gratitude to all the amazing contributors who have made MANI + + Ayush215mb @@ -330,8 +339,6 @@ We extend our heartfelt gratitude to all the amazing contributors who have made Ayush Yadav - - AliGates915 @@ -367,6 +374,8 @@ We extend our heartfelt gratitude to all the amazing contributors who have made Mohit Rana + + MutiatBash @@ -374,8 +383,6 @@ We extend our heartfelt gratitude to all the amazing contributors who have made Bashua Mutiat - - Sapna127 diff --git a/backend/.env.example b/backend/.env.example index 42b74fd4..b79381da 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,4 +1,7 @@ MONGO_URI=enter_your_mongo_uri EMAIL_USER=your_gmail EMAIL_PASS=your_16_digit_pass -JWT_SECRET=secret \ No newline at end of file +JWT_SECRET=secret +GOOGLE_CLIENT_ID=your_google_client_id +GOOGLE_CLIENT_SECRET=your_google_client_secret +FRONTEND_URL=your_frontend_url \ No newline at end of file diff --git a/backend/config/oauth.config.js b/backend/config/oauth.config.js new file mode 100644 index 00000000..651df83c --- /dev/null +++ b/backend/config/oauth.config.js @@ -0,0 +1,39 @@ +const GoogleStrategy = require("passport-google-oauth20").Strategy; +const passport = require("passport"); +const Customer = require("../models/customer.model"); // Adjust the path as needed +const config = require("./secret"); // Import your secrets (client ID, client secret) + +passport.use( + new GoogleStrategy( + { + clientID: process.env.GOOGLE_CLIENT_ID || config.GOOGLE_CLIENT_ID, + clientSecret: + process.env.GOOGLE_CLIENT_SECRET || config.GOOGLE_CLIENT_SECRET, + callbackURL: "/auth/google/callback", + }, + async (accessToken, refreshToken, profile, done) => { + try { + // Extract the email from Google profile + const email = profile.emails[0].value; + + // Search for the user in the database by email + let user = await Customer.findOne({ email }); + if (!user) { + // If user doesn't exist, create a new user + user = new Customer({ + name: profile.displayName || "Unamed User", + email: email, // Email from Google profile + }); + await user.save(); + } + // Return the user if exists or after creation + return done(null, user); + } catch (error) { + console.error("Error during Google authentication:", error); + return done(null, false, { message: "Authentication failed" }); + } + } + ) +); + +module.exports = passport; diff --git a/backend/config/passport.config.js b/backend/config/passport.config.js index ec2bf4a1..6bfae9ac 100644 --- a/backend/config/passport.config.js +++ b/backend/config/passport.config.js @@ -4,12 +4,14 @@ const passport = require("passport"); const config = require("./secret"); const Customer = require("../models/customer.model"); const Admin = require("../models/admin.model"); +require("./oauth.config"); // Secret key to sign the JWT token const secret = config.JWT_SECRET; const opts = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: secret, + secretOrKey: process.env.JWT_SECRET || secret, + algorithms: ["HS256"], }; passport.use( diff --git a/backend/config/secret.js b/backend/config/secret.js index 031c6a28..793089f1 100644 --- a/backend/config/secret.js +++ b/backend/config/secret.js @@ -2,10 +2,16 @@ const JWT_SECRET = process.env.JWT_SECRET; const MONGO_URI = process.env.MONGO_URI; const PORT = process.env.PORT; const CORS_ORIGIN = process.env.CORS_ORIGIN; +const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID; +const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; +const FRONTEND_URL = process.env.FRONTEND_URL; module.exports = { JWT_SECRET, MONGO_URI, PORT, CORS_ORIGIN, + GOOGLE_CLIENT_ID, + GOOGLE_CLIENT_SECRET, + FRONTEND_URL, }; diff --git a/backend/controller/googleOAuth.controller.js b/backend/controller/googleOAuth.controller.js new file mode 100644 index 00000000..83541525 --- /dev/null +++ b/backend/controller/googleOAuth.controller.js @@ -0,0 +1,29 @@ +const secret = require("../config/secret"); +const jwt = require("jsonwebtoken"); +const jwtSecret = secret.JWT_SECRET; + +const handleGoogleOAuth = async (req, res) => { + const token = jwt.sign( + { + sub: req.user._id, + email: req.user.email, + iat: Math.floor(Date.now() / 1000), + aud: "play-cafe", + }, + jwtSecret, + { + expiresIn: "1d", + algorithm: "HS256", + } + ); + + res.cookie("authToken", token, { + maxAge: 3600000, + secure: true, + }); + res.redirect(process.env.FRONTEND_URL || "http://localhost:3000"); +}; + +module.exports = { + handleGoogleOAuth, +}; diff --git a/backend/index.js b/backend/index.js index 7092f588..13f50cc8 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,12 +1,11 @@ const express = require("express"); +require("dotenv").config(); const cors = require("cors"); const mongoose = require("mongoose"); -const dotenv = require("dotenv"); const logger = require("./config/logger"); const errorMiddleware = require("./middlewares/errrorMiddleware"); const passport = require("passport"); - -dotenv.config(); +const { handleGoogleOAuth } = require("./controller/googleOAuth.controller"); const app = express(); const port = process.env.PORT || 3000; @@ -49,6 +48,14 @@ app.use(passport.initialize()); // API routes app.use("/api", require("./routes/index")); +app.get( + "/auth/google/callback", + passport.authenticate("google", { + failureRedirect: "/login", + session: false, + }), + handleGoogleOAuth +); app.options("*", cors(corsOptions)); diff --git a/backend/middlewares/authAdmin.js b/backend/middlewares/authAdmin.js index a5e160ed..106ae055 100644 --- a/backend/middlewares/authAdmin.js +++ b/backend/middlewares/authAdmin.js @@ -6,17 +6,13 @@ const authenticateAdmin = (req, res, next) => { if (token) { try { const decoded = jwt.verify(token, process.env.JWT_SECRET); - console.log(decoded.role); + // Remove console.log or replace with logger.debug if needed if (decoded.role !== "admin") { - logger.error( - `Unauthorized access to admin route: ${JSON.stringify(decoded.sub)}` - ); - return res.status(401).json({ error: "Unauthorized access" }); + return res.status(401).json({ error: "Forbidden" }); } - logger.info(`Admin authenticated: ${JSON.stringify(decoded.sub)}`); + next(); } catch (error) { - logger.error(`Error authenticating admin: ${error}`); return res.status(401).json({ error: "Unauthorized access" }); } } else { diff --git a/backend/package.json b/backend/package.json index f77102a4..763337ac 100644 --- a/backend/package.json +++ b/backend/package.json @@ -23,6 +23,7 @@ "mongoose": "^8.7.0", "nodemailer": "^6.9.15", "passport": "^0.7.0", + "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "validator": "^13.12.0", "winston": "^3.14.2", diff --git a/backend/routes/customerRouter.js b/backend/routes/customerRouter.js index 9fd05fb3..5a57513c 100644 --- a/backend/routes/customerRouter.js +++ b/backend/routes/customerRouter.js @@ -6,6 +6,7 @@ const { } = require("../controller/customer.controller"); const authenticateCustomer = require("../middlewares/authCustomer"); const passport = require("../config/passport.config"); +const { handleGoogleOAuth } = require("../controller/googleOAuth.controller"); const router = express.Router(); require("dotenv").config(); @@ -26,6 +27,11 @@ router.get( ); router.post("/register", createCustomer); +router.get( + "/auth/google", + passport.authenticate("google", { scope: ["email"] }) +); + router.post("/login", loginCustomer); router.post("/reset-password", resetPassword); diff --git a/backend/routes/index.js b/backend/routes/index.js index 63bcbbfb..27a2b8bd 100644 --- a/backend/routes/index.js +++ b/backend/routes/index.js @@ -1,5 +1,12 @@ const express = require("express"); const logger = require("../config/logger"); // Import your Winston logger +require("dotenv").config(); + +const config = { + JWT_SECRET: process.env.JWT_SECRET, + GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, + GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, +}; const router = express.Router(); @@ -46,6 +53,5 @@ router.use("/feedback", feedbackRouter); router.use("/user", require("./customerRouter")); router.use("/reservation", require("./reservationRouter")); router.use("/newsletter", require("./newsletterRoute")); -router.use("/forgot", require("./forgotRouter")) - +router.use("/forgot", require("./forgotRouter")); module.exports = router; diff --git a/frontend/src/components/Pages/Login.jsx b/frontend/src/components/Pages/Login.jsx index 537c8f6b..c8428034 100644 --- a/frontend/src/components/Pages/Login.jsx +++ b/frontend/src/components/Pages/Login.jsx @@ -1,11 +1,10 @@ - -import React, { useState , useEffect } from "react"; -import photo from "../../assets/login.png"; -import { Link, useNavigate } from "react-router-dom"; -import { message } from "antd"; -import Cookies from 'js-cookie' -import { FaEye } from "react-icons/fa"; -import { FaEyeSlash } from "react-icons/fa6"; +import React, { useState, useEffect } from 'react'; +import photo from '../../assets/login.png'; +import { Link, useNavigate } from 'react-router-dom'; +import { message } from 'antd'; +import Cookies from 'js-cookie'; +import { FaEye } from 'react-icons/fa'; +import { FaEyeSlash } from 'react-icons/fa6'; const Login = () => { const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3000'; @@ -13,7 +12,7 @@ const Login = () => { email: '', password: '', }); - const [hidden, setHidden] = useState(true) + const [hidden, setHidden] = useState(true); const handleChange = (e) => { setData({ ...data, [e.target.name]: e.target.value }); @@ -39,9 +38,9 @@ const Login = () => { throw new Error(result.message || 'Login failed'); } // Handle successful login (e.g., store token, redirect) - Cookies.set('authToken',result.token,{ - expire:'1h', - secure:true + Cookies.set('authToken', result.token, { + expire: '1h', + secure: true, }); message.success('Login successful'); navigate('/'); @@ -83,17 +82,20 @@ const Login = () => { className="input w-full h-10 rounded-md border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[15px] font-semibold text-[#323232] p-2.5 focus:outline-none focus:border-[#2d8cf0] placeholder-[#666] placeholder-opacity-80" name="password" placeholder="Password" - type={hidden ? "password" : "text"} + type={hidden ? 'password' : 'text'} onChange={(e) => handleChange(e)} /> - - +
Forgot Password?
@@ -104,10 +106,21 @@ const Login = () => { Register Here +
+ + {error &&

{error}

} diff --git a/frontend/src/components/Pages/Signup.jsx b/frontend/src/components/Pages/Signup.jsx index 09b04259..763a692d 100644 --- a/frontend/src/components/Pages/Signup.jsx +++ b/frontend/src/components/Pages/Signup.jsx @@ -1,11 +1,10 @@ - -import { useState , useEffect } from "react"; -import photo from "../../assets/login.png"; -import { useNavigate } from "react-router-dom"; -import { Link } from "react-router-dom"; -import { FaEye } from "react-icons/fa"; -import { FaEyeSlash } from "react-icons/fa6"; -import zxcvbn from "zxcvbn"; // Import zxcvbn for password strength check +import { useState, useEffect } from 'react'; +import photo from '../../assets/login.png'; +import { useNavigate } from 'react-router-dom'; +import { Link } from 'react-router-dom'; +import { FaEye } from 'react-icons/fa'; +import { FaEyeSlash } from 'react-icons/fa6'; +import zxcvbn from 'zxcvbn'; // Import zxcvbn for password strength check const Signup = () => { const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3000'; @@ -18,12 +17,12 @@ const Signup = () => { email: '', password: '', }); - const [hidden, setHidden] = useState(true) + const [hidden, setHidden] = useState(true); const handleChange = (e) => { setData({ ...data, [e.target.name]: e.target.value }); - if (e.target.name === "password") { + if (e.target.name === 'password') { const result = zxcvbn(e.target.value); setPasswordStrength(result.score); // Update password strength score } @@ -81,17 +80,17 @@ const Signup = () => { } }; - useEffect(() => { - window.scrollTo(0, 0); - }, []); + useEffect(() => { + window.scrollTo(0, 0); + }, []); const getPasswordStrengthColor = (score) => { - const colors = ["#ff4d4d", "#ff944d", "#ffd24d", "#d2ff4d", "#4dff88"]; + const colors = ['#ff4d4d', '#ff944d', '#ffd24d', '#d2ff4d', '#4dff88']; return colors[score]; }; const getPasswordStrengthText = (score) => { - const strengthLevels = ["Very Weak", "Weak", "Okay", "Good", "Strong"]; + const strengthLevels = ['Very Weak', 'Weak', 'Okay', 'Good', 'Strong']; return strengthLevels[score]; }; @@ -138,20 +137,29 @@ const Signup = () => { className="input w-full h-10 rounded-md border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[15px] font-semibold text-[#323232] p-2.5 focus:outline-none focus:border-[#2d8cf0] placeholder-[#666] placeholder-opacity-80" name="password" placeholder="Password" - type={hidden ? "password" : "text"} + type={hidden ? 'password' : 'text'} onChange={(e) => handleChange(e)} /> - {/* Password Strength Meter */}
-
+

Strength: {getPasswordStrengthText(passwordStrength)}

@@ -168,8 +176,19 @@ const Signup = () => { Login + + +