zhlajiex's picture
Production Fix: Resolve fs ReferenceError in Multer, fix profile auth failure, and optimize controller lookups
5db933c
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');
};