Search code examples
node.jsmongodbmongoosevalidationerror

"Path 'hashed_password' is required" even though hash_password field is full when using virtual field


I am trying to create an app where the password is sent into a virtual field, then hashed and stored as a hash. However I keep getting this error:

(node:32101) UnhandledPromiseRejectionWarning: ValidationError: User validation failed: hashed_password: Path `hashed_password` is required.

Below is my code and when I run it, I get the logs included below the code.

const mongoose = require('mongoose');
const uuidv1 = require('uuid/v1');
const cryptop = require('crypto');

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        trim: true,
        required: true
    },
    email: {
        type: String,
        trim: true,
        required: true
    },
    hashed_password: {
        type: String,
        required: true
    },
    salt: String,
    created: {
        type: Date,
        default: Date.now
    },
    updated: Date
});

userSchema
    .virtual("password")
    .set(password => {
        // create temporary variable called _password
        this._password = password;
        // generate a timestamp
        this.salt = uuidv1();
        // encryptPassword()
        this.hashed_password = this.encryptPassword(password);
        console.log(this);
    })
    .get(function () {
        return this._password;
    });

userSchema.methods = {
    encryptPassword: password => {
        if (!password) return "";
        try {
            return crypto
                .createHmac("sha1", this.salt)
                .update(password)
                .digest("hex");
        } catch (err) {
            return "";
        }
    }
};

module.exports = mongoose.model("User", userSchema);

Error:

Express is listening on port 8080
DB connected
{ name: 'Ryan', email: '[email protected]', password: 'rrrrr' }
(node:32477) UnhandledPromiseRejectionWarning: TypeError: this.encryptPassword is not a function

When I do it without the encryptPassword function, I still get an error:

const mongoose = require('mongoose');
const uuidv1 = require('uuid/v1');
const cryptop = require('crypto');

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        trim: true,
        required: true
    },
    email: {
        type: String,
        trim: true,
        required: true
    },
    hashed_password: {
        type: String,
        required: true
    },
    salt: String,
    created: {
        type: Date,
        default: Date.now
    },
    updated: Date
});

userSchema
    .virtual("password")
    .set(password => {
        // create temporary variable called _password
        this._password = password;
        // generate a timestamp
        this.salt = uuidv1();
        // encryptPassword()
        // this.hashed_password = this.encryptPassword(password);
        this.hashed_password = 'Test hash';
        console.log(this);
    })
    .get(function () {
        return this._password;
    });

userSchema.methods = {
    encryptPassword: password => {
        if (!password) return "";
        try {
            return crypto
                .createHmac("sha1", this.salt)
                .update(password)
                .digest("hex");
        } catch (err) {
            return "";
        }
    }
};

module.exports = mongoose.model("User", userSchema);

Error:

Express is listening on port 8080
DB connected
{ name: 'Ryan', email: '[email protected]', password: 'rrrrr' }
{
  _password: 'rrrrr',
  salt: 'ff790ca0-34f0-11ea-9394-a53427d4f6bb',
  hashed_password: 'Test hash'
}
(node:32577) UnhandledPromiseRejectionWarning: ValidationError: User validation failed: hashed_password: Path `hashed_password` is required.

Solution

  • Try using function(password) instead of password =>.

    When you use an arrow function, this is not referring to the user you are saving, which is also why you aren’t seeing name and email when you console log it.