diff --git a/backend/controllers/authController.js b/backend/controllers/authController.js index 0963014..efd87a3 100644 --- a/backend/controllers/authController.js +++ b/backend/controllers/authController.js @@ -1,4 +1,6 @@ import User from '../models/User.js'; +import crypto from 'crypto'; // For generating OTP +import nodemailer from 'nodemailer'; import { hashPassword, comparePassword, generateToken, verifyToken, addCookie, getCookies, removeCookie } from '../utils/authFunctions.js'; export const registerUser = async (req, res) => { @@ -19,21 +21,30 @@ export const registerUser = async (req, res) => { return res.status(400).json({ error: 'User already exists' }); } + const otp = crypto.randomInt(100000, 999999).toString(); // Generate OTP (6 digits) + if (isGoogle == true) { const newUser = new User({ name, email, phoneNumber: phoneNumber ? phoneNumber : '', - password: '' + password: '', + otp: otp, + otpExpiry: Date.now() + 3600000, // OTP expires in 1 hour }); await newUser.save(); - const token = await generateToken(newUser._id); + await sendOtpEmail(email, otp); // Send OTP to the user's email + const token = await generateToken(newUser._id); addCookie(res, 'token', token); - return res.status(201).json({ message: 'User registered successfully', userId: newUser._id , token: token }); + return res.status(201).json({ + message: 'User registered successfully. Please check your email for the OTP to verify your email.', + userId: newUser._id, + token: token, + }); } else { const hashedPassword = await hashPassword(password); @@ -41,23 +52,87 @@ export const registerUser = async (req, res) => { name, email, phoneNumber: phoneNumber ? phoneNumber : '', - password: hashedPassword + password: hashedPassword, + otp: otp, + otpExpiry: Date.now() + 3600000, // OTP expires in 1 hour }); await newUser.save(); - const token = await generateToken(newUser._id); + await sendOtpEmail(email, otp); // Send OTP to the user's email + const token = await generateToken(newUser._id); addCookie(res, 'token', token); - res.status(201).json({ message: 'User registered successfully', userId: newUser._id, token: token }); + res.status(201).json({ + message: 'User registered successfully. Please check your email for the OTP to verify your email.', + userId: newUser._id, + token: token, + }); + } + } catch (error) { + console.error(error); + res.status(500).json({ error: error.message || 'Internal Server Error' }); + } +}; + +const sendOtpEmail = async (userEmail, otp) => { + try { + const transporter = nodemailer.createTransport({ + service: 'gmail', // Or use another email provider + auth: { + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_PASS, + }, + }); + + const mailOptions = { + from: process.env.EMAIL_USER, + to: userEmail, + subject: 'Email Verification - Station Sarthi', + text: `Your OTP for email verification is: ${otp}`, + }; + + await transporter.sendMail(mailOptions); + } catch (error) { + console.error('Error sending email:', error); + throw new Error('Failed to send OTP'); + } +}; + +export const verifyOtp = async (req, res) => { + try { + const { email, otp } = req.body; + + const user = await User.findOne({ email }); + if (!user) { + return res.status(404).json({ error: 'User not found' }); } + + // Check if OTP has expired + if (Date.now() > user.otpExpiry) { + return res.status(400).json({ error: 'OTP has expired' }); + } + + // Check if OTP is correct + if (user.otp !== otp) { + return res.status(400).json({ error: 'Invalid OTP' }); + } + + // OTP is correct, mark user as verified + user.isVerified = true; + user.otp = null; // Clear OTP after verification + user.otpExpiry = null; // Clear OTP expiry after verification + await user.save(); + + res.status(200).json({ message: 'Email verified successfully' }); } catch (error) { console.error(error); res.status(500).json({ error: error.message || 'Internal Server Error' }); } }; + export const loginUser = async (req, res) => { try { const { email, password } = req.body; diff --git a/backend/models/User.js b/backend/models/User.js index ca95f98..1fa0796 100644 --- a/backend/models/User.js +++ b/backend/models/User.js @@ -40,6 +40,10 @@ const userSchema = new Schema({ otpExpiry: { type: Date, // The OTP expiry timestamp required: false, + }, + isVerified: { + type: Boolean, + default: false, // This field will be set to true once the email is verified } }, { timestamps: true diff --git a/backend/routes/authRoutes.js b/backend/routes/authRoutes.js index 8f17bc1..50b0ed4 100644 --- a/backend/routes/authRoutes.js +++ b/backend/routes/authRoutes.js @@ -5,6 +5,7 @@ import { loginUser, logoutUser, verifyUser, + verifyOtp, } from "../controllers/authController.js"; import { createCloakroomBooking } from "../controllers/cloakroomController.js"; import { createWheelchairBooking } from "../controllers/WheelchairController.js"; @@ -24,6 +25,8 @@ const loginLimiter = rateLimit({ // Register route router.post("/register", registerUser); +router.post("/verify-otp", verifyOtp); + // Login route with rate limiter router.post("/login", loginLimiter, loginUser);