224 lines
6.1 KiB
JavaScript
224 lines
6.1 KiB
JavaScript
|
// noinspection SpellCheckingInspection
|
||
|
|
||
|
import User from '../models/User.js'
|
||
|
import asyncHandler from '../middleware/async.js'
|
||
|
import ErrorResponse from '../utils/errorResponse.js'
|
||
|
import sendEmail from '../utils/sendEmail.js'
|
||
|
import crypto from 'crypto'
|
||
|
|
||
|
// @desc Register user
|
||
|
// @route POST /api/v1/auth/register
|
||
|
// @access Public
|
||
|
export const register = asyncHandler(async (req, res, next) => {
|
||
|
const { name, displayName, email, password, role } = req.body
|
||
|
|
||
|
//Create user
|
||
|
const user = await User.create({
|
||
|
name,
|
||
|
displayName,
|
||
|
email,
|
||
|
password,
|
||
|
role,
|
||
|
gamesCreated: [],
|
||
|
gamesToAccess: [],
|
||
|
})
|
||
|
|
||
|
sendTokenResponse(user, 200, res)
|
||
|
})
|
||
|
|
||
|
// @desc Login user
|
||
|
// @route POST /api/v1/auth/login
|
||
|
// @access Public
|
||
|
export const login = asyncHandler(async (req, res, next) => {
|
||
|
const { email, password } = req.body
|
||
|
|
||
|
// Validate email & password
|
||
|
if (!email || !password)
|
||
|
return next(new ErrorResponse('Please provide an email and password', 400))
|
||
|
|
||
|
// Check for user
|
||
|
const user = await User.findOne({ email }).select('+password')
|
||
|
|
||
|
if (!user) return next(new ErrorResponse('Invalid credentials', 401))
|
||
|
|
||
|
// Check is password matches
|
||
|
const isMatched = await user.matchPassword(password)
|
||
|
|
||
|
if (!isMatched) return next(new ErrorResponse('Invalid credentials', 401))
|
||
|
|
||
|
sendTokenResponse(user, 200, res)
|
||
|
})
|
||
|
|
||
|
// @desc Logout User / Clear Cookie
|
||
|
// @route GET /api/v1/auth/logout
|
||
|
// @access Private
|
||
|
export const logout = asyncHandler(async (req, res, next) => {
|
||
|
res.cookie('token', 'none', {
|
||
|
expires: new Date(Date.now() + 10 * 1000),
|
||
|
httpOnly: true,
|
||
|
})
|
||
|
|
||
|
res.status(200).json({
|
||
|
success: true,
|
||
|
data: {},
|
||
|
})
|
||
|
})
|
||
|
|
||
|
// @desc Get current logged-in user
|
||
|
// @route POST /api/v1/auth/me
|
||
|
// @access Private
|
||
|
export const getMe = asyncHandler(async (req, res, next) => {
|
||
|
const user = await User.findById(req.user.id)
|
||
|
|
||
|
res.status(200).json({
|
||
|
success: true,
|
||
|
data: user,
|
||
|
})
|
||
|
})
|
||
|
|
||
|
// @desc Update user details
|
||
|
// @route PUT /api/v1/auth/updatedetails
|
||
|
// @access Private
|
||
|
export const updateDetails = asyncHandler(async (req, res, next) => {
|
||
|
const fieldsToUpdate = {
|
||
|
name: req.body.name,
|
||
|
displayName: req.body.displayName,
|
||
|
email: req.body.email,
|
||
|
role: req.body.role,
|
||
|
updateDate: Date.now(),
|
||
|
}
|
||
|
const user = await User.findByIdAndUpdate(req.user.id, fieldsToUpdate, {
|
||
|
new: true,
|
||
|
runValidators: true,
|
||
|
})
|
||
|
|
||
|
res.status(200).json({
|
||
|
success: true,
|
||
|
data: user,
|
||
|
})
|
||
|
})
|
||
|
|
||
|
// @desc Update password
|
||
|
// @route PUT /api/v1/auth/updatepassword
|
||
|
// @access Private
|
||
|
export const updatePassword = asyncHandler(async (req, res, next) => {
|
||
|
const user = await User.findById(req.user.id).select('+password')
|
||
|
|
||
|
// Check current password
|
||
|
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)
|
||
|
})
|
||
|
|
||
|
// @desc Forgot password
|
||
|
// @route POST /api/v1/auth/forgotpassword
|
||
|
// @access Public
|
||
|
export const forgotPassword = asyncHandler(async (req, res, next) => {
|
||
|
const user = await User.findOne({ email: req.body.email })
|
||
|
|
||
|
if (!user) {
|
||
|
console.error('user does not exist')
|
||
|
return res.status(200).json({
|
||
|
success: true,
|
||
|
data: 'Email has been sent',
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Get reset token
|
||
|
const resetToken = await user.getResetPasswordToken()
|
||
|
|
||
|
await user.save({ validateBeforeSave: false })
|
||
|
|
||
|
// Create reset url
|
||
|
let resetUrl
|
||
|
let message
|
||
|
if (req.get('Referrer') === undefined) {
|
||
|
const protocol = req.secure ? 'https' : 'http'
|
||
|
const host = await req.get('host')
|
||
|
resetUrl = `${protocol}://${host}/api/auth/resetpassword/${resetToken}`
|
||
|
message = {
|
||
|
text: `You are receiving this email because you (or someone else) has requested the reset of a password. Please make a PUT request to: \n\n${resetUrl}`,
|
||
|
html: `<body><p>You are receiving this email because you (or someone else) has requested the reset of a password. <br />Please make a PUT request to:</p> <p>${resetUrl}</p></body>`
|
||
|
}
|
||
|
} else {
|
||
|
resetUrl = `${req.get('Referrer')}resetpassword/${resetToken}`
|
||
|
message = {
|
||
|
text: `You are receiving this email because you (or someone else) has requested the reset of a password. \nPlease visit the below URL to continue this request. \n\n${resetUrl}`,
|
||
|
html: `<body><p>You are receiving this email because you (or someone else) has requested the reset of a password. <br />Please visit the below URL to continue this request.</p> <p><a href=${resetUrl}>${resetUrl}</a></p></body>`,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
await sendEmail({
|
||
|
email: user.email,
|
||
|
subject: 'Games Database Password Reset Token',
|
||
|
message,
|
||
|
})
|
||
|
|
||
|
res.status(200).json({
|
||
|
success: true,
|
||
|
data: 'Email has been sent',
|
||
|
})
|
||
|
} catch (err) {
|
||
|
console.log(err)
|
||
|
user.resetPasswordToken = undefined
|
||
|
user.resetPasswordExpire = undefined
|
||
|
|
||
|
await user.save({ validateBeforeSave: false })
|
||
|
|
||
|
return next(new ErrorResponse('Email could not be sent', 500))
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// @desc Reset password
|
||
|
// @route PUT /api/v1/auth/resetpassword/:resettoken
|
||
|
// @access Public
|
||
|
export const resetPassword = asyncHandler(async (req, res, next) => {
|
||
|
// Get hashed token
|
||
|
const resetPasswordToken = crypto
|
||
|
.createHash('sha256')
|
||
|
.update(req.params.resettoken)
|
||
|
.digest('hex')
|
||
|
|
||
|
const user = await User.findOne({
|
||
|
resetPasswordToken,
|
||
|
resetPasswordExpire: { $gt: Date.now() },
|
||
|
})
|
||
|
|
||
|
if (!user) return next(new ErrorResponse('Invalid token', 400))
|
||
|
|
||
|
// Set new password
|
||
|
user.password = req.body.password
|
||
|
user.resetPasswordToken = undefined
|
||
|
user.resetPasswordExpire = undefined
|
||
|
|
||
|
await user.save()
|
||
|
|
||
|
sendTokenResponse(user, 200, res)
|
||
|
})
|
||
|
|
||
|
// Get token from model, create cookie and send response
|
||
|
const sendTokenResponse = (user, statusCode, res) => {
|
||
|
// Create token
|
||
|
const token = user.getSignedJwtToken()
|
||
|
|
||
|
const options = {
|
||
|
expires: new Date(
|
||
|
Date.now() + 24 * 60 * 60 * 1000,
|
||
|
),
|
||
|
httpOnly: true,
|
||
|
}
|
||
|
|
||
|
if (Bun.env.NODE_ENV === 'production') options.secure = true
|
||
|
|
||
|
res.status(statusCode).cookie('token', token, options).json({
|
||
|
success: true,
|
||
|
token,
|
||
|
})
|
||
|
}
|