const crypto = require('crypto'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const User = require('../models/User'); const ErrorResponse = require('../utils/errorResponse'); const asyncHandler = require('../utils/asyncHandler'); const sendEmail = require('../services/emailService'); const getSignedJwtToken = (id) => { return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRE }); }; // @desc Register user // @route POST /api/auth/register // @access Public exports.register = asyncHandler(async (req, res, next) => { const { name, email, password, accessKey } = req.body; // Verify Unique Secret Access Key if (accessKey !== process.env.NEURAL_ACCESS_KEY) { return next(new ErrorResponse('Invalid Neural Access Key.', 401)); } // Create user const user = await User.create({ name, email, password, isVerified: true // Auto-verify for dev }); sendTokenResponse(user, 200, res); }); // @desc Login user // @route POST /api/auth/login // @access Public exports.login = asyncHandler(async (req, res, next) => { const { email, password } = req.body; if (!email || !password) { return next(new ErrorResponse('Please provide email and password', 400)); } const user = await User.findOne({ email }).select('+password'); if (!user || !(await user.matchPassword(password))) { return next(new ErrorResponse('Invalid credentials', 401)); } if (!user.isVerified) { return next(new ErrorResponse('Please verify your email first', 401)); } sendTokenResponse(user, 200, res); }); // @desc Get current logged in user // @route GET /api/auth/me // @access Private exports.getMe = asyncHandler(async (req, res, next) => { res.status(200).json({ success: true, data: req.user, }); }); // @desc Verify email (Dummy for compatibility) // @route GET /api/auth/verify/:token // @access Public exports.verifyEmail = asyncHandler(async (req, res, next) => { res.status(200).json({ success: true, data: 'Verified' }); }); // @desc Forgot password // @route POST /api/auth/forgotpassword // @access Public exports.forgotPassword = asyncHandler(async (req, res, next) => { const user = await User.findOne({ email: req.body.email }); if (!user) return next(new ErrorResponse('No user', 404)); const resetToken = user.getResetPasswordToken(); await user.save({ validateBeforeSave: false }); const resetUrl = `${process.env.CLIENT_URL}/resetpassword/${resetToken}`; try { await sendEmail({ email: user.email, subject: 'Codex Reset', message: resetUrl }); res.status(200).json({ success: true, data: 'Email sent' }); } catch (err) { user.resetPasswordToken = undefined; user.resetPasswordExpire = undefined; await user.save({ validateBeforeSave: false }); return next(new ErrorResponse('Email error', 500)); } }); // @desc Reset password // @route PUT /api/auth/resetpassword/:token // @access Public exports.resetPassword = asyncHandler(async (req, res, next) => { const resetPasswordToken = crypto.createHash('sha256').update(req.params.token).digest('hex'); const user = await User.findOne({ resetPasswordToken, resetPasswordExpire: { $gt: Date.now() }, }); if (!user) { return next(new ErrorResponse('Invalid token', 400)); } user.password = req.body.password; user.resetPasswordToken = undefined; user.resetPasswordExpire = undefined; await user.save(); sendTokenResponse(user, 200, res); }); // @desc Update password // @route PUT /api/auth/updatepassword // @access Private exports.updatePassword = asyncHandler(async (req, res, next) => { const user = req.user; if (!(await user.matchPassword(req.body.currentPassword))) { return next(new ErrorResponse('Password is incorrect', 401)); } user.password = req.body.newPassword; await user.save(); sendTokenResponse(user, 200, res); }); const sendTokenResponse = (user, statusCode, res) => { const token = user.getSignedJwtToken(); const options = { expires: new Date( Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000 ), httpOnly: true, }; if (process.env.NODE_ENV === 'production') { options.secure = true; } res.status(statusCode).cookie('token', token, options).json({ success: true, token, }); }; // @desc GitHub Auth Callback // @route GET /api/auth/github/callback // @access Public exports.githubAuthCallback = (req, res) => { const token = req.user.getSignedJwtToken(); const options = { expires: new Date(Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000), httpOnly: true }; if (process.env.NODE_ENV === 'production') options.secure = true; res.cookie('token', token, options); // Redirect to chat or home res.redirect('/chat'); };