import bcrypt from "bcrypt"; import jwt from "jsonwebtoken"; import User from "../models/user.model.js"; import { sendResetPasswordMail, sendSignupMail, } from "../utils/mailer.js"; import crypto from "crypto"; export async function signup(req, res) { try { const { email, password } = req.body; if (!email || !password) return res.status(400).json({ error: "Email and password required" }); const exists = await User.findOne({ email }); if (exists) return res.status(400).json({ error: "User already exists" }); const passwordHash = await bcrypt.hash(password, 10); const user = await User.create({ email, passwordHash }); // ✅ send confirmation email (non-blocking) sendSignupMail(email) .then(() => console.log("Signup email sent to", email)) .catch(err => console.error("Email send failed:", err)); res.status(201).json({ message: "Signup success, email sent", id: user._id }); } catch (err) { console.error(err); res.status(500).json({ error: "Signup failed" }); } } export async function login(req, res) { try { const { email, password } = req.body; const user = await User.findOne({ email }); if (!user) return res.status(401).json({ error: "Invalid credentials" }); const match = await bcrypt.compare(password, user.passwordHash); if (!match) return res.status(401).json({ error: "Invalid credentials" }); const token = jwt.sign( { id: user._id, email: user.email }, process.env.JWT_SECRET, { expiresIn: "1h" } ); res.json({ message: "Login success", token }); } catch (err) { console.error(err); res.status(500).json({ error: "Login failed" }); } } /** * POST /api/auth/change-password * Body: { currentPassword, newPassword } * Header: Authorization: Bearer */ export async function changePassword(req, res) { try { const { currentPassword, newPassword } = req.body; // if using FormData, fields come from req.body AFTER a multipart parser if (!currentPassword || !newPassword) { return res.status(400).json({ error: "Current password and new password are required" }); } const user = await User.findById(req.user.id); if (!user) return res.status(404).json({ error: "User not found" }); const isMatch = await bcrypt.compare(currentPassword, user.passwordHash); if (!isMatch) return res.status(401).json({ error: "Current password is incorrect" }); user.passwordHash = await bcrypt.hash(newPassword, 10); await user.save(); res.json({ message: "Password updated successfully" }); } catch (err) { console.error("changePassword error:", err); // ✅ show actual error res.status(500).json({ error: "Failed to change password" }); } } /** * POST /api/auth/forgot-password * Body: { email } */ export async function forgotPassword(req, res) { try { const { email } = req.body; if (!email) return res.status(400).json({ error: "Email is required" }); const user = await User.findOne({ email }); if (!user) return res.json({ message: "If the email is registered, a reset link has been sent.", verificationCode: null, // user not found }); // Generate 4-digit numeric verification code const verificationCode = Math.floor(1000 + Math.random() * 9000).toString(); // Save code and expiry in DB user.resetPasswordToken = verificationCode; user.resetPasswordExpires = Date.now() + 60 * 60 * 1000; // 1 hour await user.save(); // Send code via email await sendResetPasswordMail(email, verificationCode); // ✅ Return verification code in response res.json({ message: "If the email is registered, a reset link has been sent.", verificationCode, // This is the 4-digit code }); } catch (err) { console.error("forgotPassword error:", err); res.status(500).json({ error: "Failed to send reset link" }); } } /** * POST /api/auth/reset-password * Body: { token, newPassword } */ export async function resetPassword(req, res) { try { const { token, newPassword } = req.body; if (!token || !newPassword) return res.status(400).json({ error: "Token and new password are required" }); const user = await User.findOne({ resetPasswordToken: token, resetPasswordExpires: { $gt: Date.now() }, }); if (!user) return res.status(400).json({ error: "Invalid or expired token" }); user.passwordHash = await bcrypt.hash(newPassword, 10); user.resetPasswordToken = undefined; user.resetPasswordExpires = undefined; await user.save(); res.json({ message: "Password has been reset successfully" }); } catch (err) { console.error("resetPassword error:", err); res.status(500).json({ error: "Failed to reset password" }); } }