Getting NULL after awaiting 'findOne' query - javascript

This is the code for login authorization
exports.login = catchAsync(async(req, res, next) => {
// const { email, password } = req.body;
const email = req.body.email;
const password = req.body.password;
// 1. check if the email and password exist
if (!email || !password) {
return next(new AppError('please provide password or email!', 400));
}
// 2. check if the email and password are corrects
const user = await User.findOne({ email }).select('+password');
const correct = await user.correctPassword(password,user.password);
if (!user || !correct) {
return next(new AppError('please enter valid email or password', 401));
}
// 3. if all ok, send token to client
const token = '';
res.status(200).json({
status: 'sucess',
token,
user,
});
});
the code is looking correct!
assigning null to the user after await findone query

Related

Why can't I clear cookies in express

cookies just keeps adding on and on when I register a new user.
userRoutes.js:
const { registerUser, loginUser, registerVerify } = require("./userController");
const express=require('express')
const router=express.Router()
router
.route('/register')
.post(registerUser)
module.exports=router
userController.js:
const User = require("./userModel");
const validator = require("validator");
const jwt=require('jsonwebtoken')
const sendToken = function (email) {
let data = {
expiresIn: process.env.JWT_EXPIRE_SHORT,
email,
};
let token = jwt.sign(data, process.env.JWT_SECRET_KEY);
return token;
};
exports.registerUser = async (req, res, next) => {
try {
const { userName, email, password, confirmPassword } = req.body;
let user = [
{ userName, email, password, confirmPassword, createdAt: Date.now() },
];
//passwords do not match error
if (password !== confirmPassword) {
throw "Password doesn't match Confirm Password.";
}
//email not valid error
if (!validator.isEmail(email)) {
throw "Email not valid.";
}
//user already logged in error
if (await User.findOne({ email })) {
throw "User already exists. Please login";
}
//create user
await User.create(user);
//assign token
let token = sendToken(email);
//clear cookie
res.status(200).clearCookie('token').cookie(token, 'token', {maxAge: 360000}).json({
message: "Please fill the required text send via email",
token,
});
} catch (err) {
// console.log(err)
res.status(400).json({
message: "Signup Not Successfull",
err,
});
}
};
I've tried:
router
.route('/register',{ credentials: 'same-origin'})
.post(registerUser)
router
.route('/register',{ credentials: 'include'})
.post(registerUser)
router
.route('/register',{ withCredentials: true})
.post(registerUser)
Here is the correct way for creating a cookie:
res.cookie('token', token, {maxAge: 360000});
Note: You don't need to clear and create a new one.
when you send a cookie with the same key it overrides itself.

Why in this login page backend server accept all the password if I give wrong password then it also accept

I put the wrong password but it gets login successfully and the data which is inside a particular user is as a new user login. I want you to please tell me a error.
Link of an online hosted project: NOTEBOOK/login
Link of GitHub repository: GITHUB/notebook
The login folder is inside routes/auth.js
const express = require('express');
const router = express.Router();
const User = require('../models/User')
const { body, validationResult } = require('express-validator');
var bcrypt = require('bcryptjs');
var jwt = require('jsonwebtoken');
let fetchuser = require('../middleware/fetchuser')
const dotenv = require('dotenv');
dotenv.config();
const secret=process.env.YOUR_SECRET
router.post('/login', [
body('email', 'Enter a valid Email').isEmail(),
body('password', 'Password cannot be blank').exists()
], async (req, res) => {
let success=false;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
// check whether user with this email exist
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({success, error: "Please login using correct credentials" })
};
let passwordCompare = bcrypt.compare(password, user.password);
if (!passwordCompare) {
return res.status(400).json({success, error: "Please login using correct credentials" })
};
const data = {
user: {
id: user.id
}
}
var authtoken = jwt.sign(data, secret);
success=true;
res.json({success, authtoken })
} catch (error) {
console.log(error.message);
res.status(500).send("Internal server error has occured")
}
})
you need to wait for the promise to resolve, you can opt for any of the below options
const passwordCompare = await bcrypt.compare(password, user.password);
OR
const passwordCompare = bcrypt.compareSync(password, user.password);
OR
bcrypt.compare(password, user.password).then(function(result) {
// result == true
});

Bcrypt reset password not saving the updated password

I'm working on my password reset flow and everything works except the actual bcrypt password reset. Following the "Technique 2 (auto-gen a salt and hash)" from about halfway down in the bcrypt docs suggests following below syntax:
Bcrypt docs syntax
const hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
// Store hash in your password DB.
My function
module.exports.submitNewPassword = async (req, res) => {
// console.log(req.body.password, req.params, req.headers.referer );
const slidedHeaderToken = req.headers.referer.slice(-40);
const user = await User.findOne({ resetPasswordToken: slidedHeaderToken, resetPasswordExpires: { $gt: Date.now() } });
console.log("submitNewPassword user ", user);
if (!user) {
console.log("user not found");
req.flash('error', "Password reset token is invalid or has expired");
res.render('users/reset')
} else {
// hash the new password
const hashedPassword = await bcrypt.hash(req.body.password, 12);
// update the user's password
user.password = hashedPassword;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
await user.save();
res.redirect('/users/login');
}
}
The resetPasswordToken and resetPasswordExpires are set properly in my previous function which emails out the password reset link and saves the two variables to the database.
The if statement logic and user.resetPasswordToken = undefined; and user.resetPasswordExpires = undefined; are executed properly but I can't get user.password = hashedPassword; to work.
How do I reset the user's password?

Password reset token is invalid or has been expired in Node.js

It's me again asking for help in Nodejs. I tried processing the resetPassword function that I created on Nodejs using Postman but I kept having the same error. I also noticed from my MongoDB Compass that the resetPasswordToken on the database and the resetPasswordToken sent using mailtrap is not the same. Here are my codes:
//user.js
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const crypto = require('crypto')
const userSchema = new mongoose.Schema({
name:{
type: String,
required: [true, 'Please enter your name'],
maxLength: [30, 'Your name cannot exceed 30 characters']
},
email:{
type: String,
required: [true, ' Please enter your email'],
unique: true,
validate:[validator.isEmail, 'Please enter a valid email address.']
},
password:{
type:String,
required: [true, 'Please enter your password'],
minlength: [6, 'Your password must be longer that 6 characters.'],
select: false
},
role:{
type: String,
default: 'admin'
},
createdAt: {
type: Date,
default:Date.now
},
resetPasswordToken: String,
resetPasswordExpire: Date
})
//Encrypting password before saving user
userSchema.pre('save',async function(next){
if(!this.isModified('password')){
next()
}
this.password = await bcrypt.hash(this.password, 10)
})
//Compare user password
userSchema.methods.comparePassword = async function(enteredPassword){
return await bcrypt.compare(enteredPassword, this.password)
}
//Return JWT token
userSchema.methods.getJwtToken = function(){
return jwt.sign({id:this._id}, process.env.JWT_SECRET,{
expiresIn: process.env.JWT_EXPIRES_TIME
})
}
// Generate password reset token
userSchema.methods.getResetPasswordToken = function(){
//Generate token
const resetToken = crypto.randomBytes(20).toString('hex');
//Hash and set to resetPasswordToken
this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex')
//Set token expire time
this.resetpasswordExpire = Date.now() + 30 * 60 * 1000
return resetToken
}
module.exports = mongoose.model('User', userSchema);
//authController.js
const User = require('../models/user')
const ErrorHandler = require('../utils/errorHandler');
const catchAsyncErrors = require('../middlewares/catchAsynchErrors');
const sendToken = require('../utils/jwtToken');
const sendEmail = require('../utils/sendEmail')
const crypto = require('crypto')
//Register a user => /api/v1/register
exports.registerUser = catchAsyncErrors (async (req, res, next) =>{
const { name, email, password } =req.body;
const user = await User.create({
name,
email,
password
})
sendToken(user, 200, res)
})
//Login User => api/v1/login
exports.loginUser = catchAsyncErrors (async (req,res,next) =>{
const { email, password} = req.body;
//Checks if email and password is entered by user
if(!email || !password){
return next(new ErrorHandler('Please enter email and password', 400))
}
//Finding the user in database
const user = await User.findOne({email}).select('+password')
if(!user){
return next(new ErrorHandler('Invalid Email or Password', 401));
}
//Checks if password or correct or not
const isPasswordMatched = await user.comparePassword(password)
if (!isPasswordMatched) {
return next(new ErrorHandler('Invalid Email or Password', 401));
}
sendToken(user,200,res)
})
//Forgot Password => api/v1/password/forgot
exports.forgotPassword = catchAsyncErrors(async(req, res, next) => {
const user = await User.findOne({email: req.body.email});
if(!user){
return next(new ErrorHandler('User not found', 404));
}
//Get reset token
const resetToken = user.getResetPasswordToken();
await user.save({validateBeforeSave: false })
//Create reset password url
const resetUrl =`${req.protocol}://${req.get('host')}/api/v1/password/reset/${resetToken}`;
const message = `Your password reset token is as follows:\n\n${resetUrl}\n\n If you have not requested this email, then please ignore.`
try{
await sendEmail({
email: user.email,
subject: "KPOPStore Password Recovery",
message
})
res.status(200).json({
success: true,
message: `Email sent to ${user.email}`
})
}catch (error){
user.resetPasswordToken = undefined;
user.resetPasswordExpire = undefined;
await user.save({validateBeforeSave: false })
return next(new ErrorHandler(error.message, 500))
}
})
//ResetPassword => /api/v1/password/reset/:token
exports.resetPassword = catchAsyncErrors(async(req, res, next) =>{
//Hash URL Token
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 ErrorHandler('Password reset token is invalid or has been expired.', 400)
)
}
if(req.body.password !== req.body.confirmPassword){
return next(new ErrorHandler('Password does not match', 400))
}
//Setup new password
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpire = undefined;
await user.save();
sendToken(user, 200, res)
})
//Logout user => /api/v1/logout
exports.logout = catchAsyncErrors(async (req,res,next)=>{
res.cookie('token', null, {
expires: new Date(Date.now()),
httpOnly: true
})
res.status(200).json({
success: true,
message: 'Logged out'
})
})
//jwtToken.js
//Create and send token and save in cookie.
const sendToken =( user, statusCode, res)=>{
//Create Jwt token
const token = user.getJwtToken();
//Options for cookie
const options = {
expires: new Date(
Date.now() + process.env.COOKIE_EXPIRES_TIME * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.status(statusCode).cookie('token', token, options).json({
success: true,
token,
user
})
}
module.exports = sendToken;
//auth.js
const express = require('express');
const router = express.Router();
const { registerUser, loginUser, logout, forgotPassword, resetPassword} = require('../controllers/authController')
router.route('/register').post(registerUser);
router.route('/login').post(loginUser);
router.route('/password/forgot').post(forgotPassword)
router.route('/password/reset/:token').put(resetPassword)
router.route('/logout').get(logout);
module.exports = router;
I'm sorry for the long blocks of code. I've been stuck in this part for 3 days. Please help me again. Thank you!
It's a typo in the User model's method:
//Set token expire time
this.resetpasswordExpire = Date.now() + 30 * 60 * 1000
It sets resetpasswordExpire, not resetPasswordExpire, so the change is not picked up by the Object-Document Mapper and not saved in the DB. Then, your search fails:
User.findOne({
resetPasswordToken,
resetPasswordExpire: { $gt: Date.now() }
})
because resetPasswordExpire is not set.

Invalid Credentials Bcyrpt.compare()

const express = require('express');
const router = express.Router();
const auth = require('../../middleware/auth');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../../models/User');
// #route Get api/auth
// #desc Test route
// #access Public
router.get('/', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch(err) {
console.error(err.message);
res.status(500).send('Server Error')
}
});
// #route POST api/auth
// #desc Authenticate User And Get Token
// #access Public
router.post('/',
[
check('email', 'Please include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array()});
}
const { email, password } = req.body;
try {
// See if user exists
let user = await User.findOne({ email})
if (!user) {
return res
.status(400)
.json({ errors: [ { msg: 'Invalid Credentials Email' } ] });
}
// Make Sure Password matches
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch) {
return res
.status(400)
.json({ errors: [ { msg: 'Invalid Credentials Password' } ] });
}
const payload = {
user: {
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: 360000 },
(err, token) => {
if(err) throw err;
res.json({ token });
}
);
} catch(err) {
console.error(err.message);
res.status(500).send('Server error')
}
});
module.exports = router
In my database I have email and password
in my postman when i make POST request to https://localhost:5000/api/auth
the email is correct however I keep getting password is not correct with this const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch) {
return res
.status(400)
.json({ errors: [ { msg: 'Invalid Credentials Password' } ] });
}
i console logged both password and user.password and it is the same value, i dont understand why !isMatch is keep getting triggered
can anyone help me
The syntax of bcrypt.compare() is:
bcrypt.compare(plaintextPassword, hash)...
The first parameter is plaintext password and second is hash of the real password so it will not be the same value. As you mentioned that your password and user.password is the same value, I guess you forgot to hash user password before saving it to the DB. Please check the docs for more details.

Categories