Search code examples
node.jsauthenticationbcryptmern

How to hash two password simultaneously using bcyrpt?


I am trying to get login page with two passwords. For only one password the code is working perfectly but when I am adding another password it is throwing error "parallel Save Error".

[0] (node:16516) UnhandledPromiseRejectionWarning: ParallelSaveError: Can't save() the same
doc multiple times in parallel. Document: 5e703180c90fbc40848fcfca

[0] (node:16516) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated 
either by throwing inside of an async function without a catch block, or by rejecting a promise which 
was not handled with .catch(). (rejection id: 2)

[0] (node:16516) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate the Node.js process with a non- 
zero exit code.

This is my user.js script:

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const config = require('config');
const jwt = require('jsonwebtoken');
const User = require('../../models/User');

router.post('/', (req, res,) => {
const { name, email, password1, password2 } = req.body;

if(!name || !email || !password1 || !password2) {
return res.status(400).json({ msg: 'Please enter all fields' });
}

User.findOne({ email })
.then(user => {
  if(user) return res.status(400).json({ msg: 'User already exists' });

  const newUser = new User({
    name,
    email,
    password1,
    password2
  });

  // Hash
  bcrypt.genSalt(10, (err, salt) => {
    bcrypt.hash(newUser.password1, salt , (err, hash) => {
      if(err) throw err;
      newUser.password1 = hash;
      newUser.save()
        .then(user => {
          jwt.sign(
            { id: user.id },
            config.get('jwtSecret'),
            { expiresIn: 3600 },
            (err, token) => {
              if(err) throw err;
              res.json({
                token,
                user: {
                  id: user.id,
                  name: user.name,
                  email: user.email
                }
              });
            }
          )
        });
     })
  })


  // Create salt & hash
  bcrypt.genSalt(10, (err, salt) => {
    bcrypt.hash(newUser.password2, salt, (err, hash) => {
      if(err) throw err;
      newUser.password2 = hash;
      newUser.save()
        .then(user => {
          jwt.sign(
            { id: user.id },
            config.get('jwtSecret'),
            { expiresIn: 3600 },
            (err, token) => {
              if(err) throw err;
              res.json({
                token,
                user: {
                  id: user.id,
                  name: user.name,
                  email: user.email
                }
              });
            }
          )
        });
     })
   })
 })
});

module.exports = router;

and the following is the code for Authentication.js

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const config = require('config');
const jwt = require('jsonwebtoken');
const auth = require('../../middleware/auth');


// User Model
const User = require('../../models/User');

router.post('/', (req, res) => {
const { email, password1, password2 } = req.body;

// for validation
if(!email || !password1 || !password2) {
return res.status(400).json({ msg: 'Please enter all fields' });
}

// Check if user exists
User.findOne({ email })
.then(user => {
  if(!user) return res.status(400).json({ msg: 'User Does not exist' });

  // Validation of password
  bcrypt.compare(password1, user.password1)
    .then(isMatch => {
      if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials' });

      jwt.sign(
        { id: user.id },
        config.get('jwtSecret'),
        { expiresIn: 3600 },
        (err, token) => {
          if(err) throw err;
          res.json({
            token,
            user: {
              id: user.id,
              name: user.name,
              email: user.email
            }
          });
        }
      )
    })
  bcrypt.compare(password2, user.password2)
    .then(isMatch => {
      if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials' });

      jwt.sign(
        { id: user.id },
        config.get('jwtSecret'),
        { expiresIn: 3600 },
        (err, token) => {
          if(err) throw err;
          res.json({
            token,
            user: {
              id: user.id,
              name: user.name,
              email: user.email
            }
          });
        }
      )
    })
 }) 
})

router.get('/user', auth, (req, res) => {
User.findById(req.user.id)
.select('-password1, -password2')
.then(user => res.json(user));
});

module.exports = router;

I am getting only password2 as a hashed password.

password1:"ddd"
password2:"$2a$10$PQhBiDtelKoRspAFn7BW0OuI0pnAyDl.DQSag6bBvYdlirBZM/oAq"

what should I need to do to remove these errors?


Solution

  • I think it's better to write the encrypt password method in the model.js and export it with the User to the route.js or whatever its name for better & clean code so you can use your method as long as you need.