2

I am unable to fetch the hash and salt values from the database. They are being stored during the sign up, but not being retrieved from the application. Attached below are the snapshots of the database, console screen that displays the retrieved information of the user (which is without the salt and hash values) and the user schema and the code used to fetch the data.

Snapshot of the user data in the database (MongoDB) Snapshot of the collection in the database (MongoDB)

snapshot of the same user data on the console Note: The isVerified is changed to true after the email is verified (The snapshot of the database was taken after the account was verified)

console snapshot

Schema method to validate the user

UserSchema.methods.validPassword = function(password) { 
    var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64, `sha512`).toString(`hex`); 
    if(this.hash === hash){
        return true;
    }
    return false;
};

Below is my user schema

const UserSchema = mongoose.Schema({
    username: {
        type: String,
        required: true
    },
    email: {
        type: String, 
        unique: true, 
        required: true
    },
    roles: {
        type: 'String', 
        default: 'user'
    },
    isVerified: {
        type: Boolean, 
        default: false
    },
    hash: String,
    salt: String,
    token: String,
    passwordResetToken: String,
    passwordResetExpires: Date
});

Code used to fetch the user

User.findOne({
  username: req.body.username
}, (err, user) => {
  console.log(user.validPassword(req.body.password) + "  <<<<-------validPassword method result");
  if (user === null) {
    req.flash("error", "The provided username is incorrect. Please try again");
    res.redirect("/login");
  }
  if (user.isVerified) {
    if (user.validPassword(req.body.password)) {
      res.redirect("/");
    } else {
      req.flash("error", "Incorrect password. Please try again");
      res.redirect("/login");
    }
  } else if (!user.isVerified) {
    console.log("user not verified");
    req.flash("error", "Please confirm your email first by clicking on the activation link that was sent to you during registration");
    res.redirect("/login");
  }
});

The error is,

The "salt" argument must be one of type string, Buffer, TypedArray, or DataView. Received type undefined`.

I believe this is because salt is not being fetched from the database.

Gaurav Thantry
  • 753
  • 13
  • 30
  • Could you also add the userSchema over here. Chances are you missed `salt` field while declaration. – georoot Aug 19 '19 at 19:47
  • Just added the schema. I had already included salt and hash in it. @georoot – Gaurav Thantry Aug 19 '19 at 19:57
  • How do you fetch the user? – Vsevolod Goloviznin Aug 20 '19 at 04:12
  • @VsevolodGoloviznin I have added the code used to fetch the user. – Gaurav Thantry Aug 20 '19 at 06:02
  • 1
    @GauravThantry I don't think you're using the methods properly, check out this doc: https://mongoosejs.com/docs/2.7.x/docs/methods-statics.html – Vsevolod Goloviznin Aug 20 '19 at 06:04
  • @VsevolodGoloviznin, findOne() gives only one document, which is what I require. As given here https://stackoverflow.com/questions/7033331/how-to-use-mongoose-findone – Gaurav Thantry Aug 20 '19 at 06:19
  • @GauravThantry you need to fetch the user inside your validatePassword method, inside the method 'this' does not refer to the object you retrieved but to the model itself – Vsevolod Goloviznin Aug 20 '19 at 06:27
  • @VsevolodGoloviznin. I will try fetching the user in the validatePassword. But in the code, I am trying to call the method on the fetched user as given in the following page https://www.geeksforgeeks.org/node-js-password-hashing-crypto-module/ I had made some temporary changes in the `isVerified` function, and I hadn't reverted. Please check now – Gaurav Thantry Aug 20 '19 at 06:34
  • @GauravThantry the guide you've sent might be using and old version of mongoose, you need to refer to the latest docs – Vsevolod Goloviznin Aug 20 '19 at 06:39
  • @VsevolodGoloviznin. Will search for a newer version, but my other question was, why isn't the salt and hash fetched from the database, when the rest are being called? – Gaurav Thantry Aug 20 '19 at 06:51
  • @GauravThantry they are fetched, you can just check it by logging `user.salt` and `user.hash` after fetching the user. As I was saying before `this` inside your `validPassword` method does not refer to the object that is fetched, but to the model itself – Vsevolod Goloviznin Aug 20 '19 at 06:54
  • @VsevolodGoloviznin, No I tried console logging it again. It is not fetching `user.salt` and `user.hash` even inside the main `findOne` function – Gaurav Thantry Aug 20 '19 at 06:58

2 Answers2

1

i had the same issued and someone told me to add .select('+salt +hash') after the original query and it worked. const user = await User.findOne({username:req.body.username}).select("+salt +hash")

DharmanBot
  • 1,066
  • 2
  • 6
  • 10
0

I'm no expert, but I think your userSchema file contains the following line

userSchema.plugin(passportLocalMongoose);

This line is the one that prevents you from fetching salt and hash. Try removing it.

LNTR
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 01 '23 at 01:36