unable hash the password in mean stack - mongodb

This is the code from routes file.
router.put('/reset/:token', function(req, res, next) {
console.log('reseting the password');
User.findOne({resetPasswordToken:req.params.token}, function(err, user) {
if(err) {
return next(err);
}
if (!user) {
return res.status(422).json({errors: [{msg: 'invalid reset token'}]});
}
user.resetPasswordToken ='';
user.resetPasswordExpires = '';
user.password = req.body.password;
User.addUser(user, (err, user) => {
if(err){
res.json({success: false, msg:'password has not changed'});
} else {
res.json({success: true, msg:'password has changed'});
}
});
});
});
This part of the code is from my schema file.
const UserSchema = mongoose.Schema({
password: {
type: String,
required: true
},
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
const User = module.exports = mongoose.model('User', UserSchema);
module.exports.addUser = function(newUser, callback){
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) throw err;
newUser.password = hash;
newUser.save(callback);
});
});
}
When I try to rest the password it is storing as I've given the input. It is not hashing the password. For example, I have given the password as "zp12345", in the database it is storing as "password" : "zp12345".

For solve the problem you need to fix your addUser method:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
module.exports.addUser = function(newUser, callback){
bcrypt.hash(newUser.password, bcrypt.genSaltSync(10), null, (err, hash) => {
if (err) {
return next(err);
}
newUser.password = hash;
newUser.save(callback);
})
};
Here there is another example: Mongoose Pre Save Changing Password
And this is the library documentation: Bcrypt Nodejs

Related

Mongoose pre save middleware is not triggering/saving hashed passwords to db

I am trying to pre save and hash password with bcrypt in mongoose in my next.js project, but password still unhashed. i tryed every link in stackoverflow and didnt solve it, the password still saved unHashed.
mongoose version: 6.9.1
this is my users.model file:
import {
models,
model,
Schema,
} from 'mongoose';
import bcrypt from 'bcrypt';
const UserSchema: Schema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
displayName: {
type: String,
required: true,
},
role: {
type: String,
},
});
UserSchema.pre('save', function (next) {
console.log('Pre-Save Hash has fired.');
let user = this;
bcrypt.genSalt(10, (err, salt) => {
if (err) console.error(err);
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
});
const UserModel = models.Users || model('Users', UserSchema, 'users');
export default UserModel;
this is my adding function file:
import dbConnect from '#/utils/mongodb';
import UserModel from '#/models/user.model';
import { NextApiRequest, NextApiResponse } from 'next';
import { MongoError } from 'mongodb';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// const { email, password } = req.query;
try {
dbConnect();
const query = req.body;
const newUser = new UserModel(query);
const addedUser= await newUser.save(function (err: MongoError) {
if (err) {
throw err;
}
});
res.status(200).json(addedUser);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
}
i cant see the 'Pre-Save Hash has fired.' in my console also..
// You need to add user.isModified("password")
userSchema.pre("save", function (next) {
var user = this;
if (user.isModified("password")) {
bcrypt.genSalt(SALT_I, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
next();
}
});
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
if (err) return cb(err);
cb(null, isMatch);
});
};
// to make register end point
import mongoose from "mongoose";
import User from "../../../models/User";
const dbConnect = async () => {
mongoose
.connect("mongodb://localhost:27017/test")
.then(() => {
console.log("Connected to mongoDb");
})
.catch((error) => {
console.log(error);
});
};
export default async function handler(req, res) {
try {
await dbConnect();
const query = req.body;
const newUser = new User(query);
await newUser.save(function (err, result) {
if (err) {
throw err;
} else {
res.status(200).json(result);
}
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
}
thanks to all.
The problem was in my dbconnect file!

Typescript Error in mongoose schemas pre method: Unexpected aliasing of 'this' to local variable

I'm trying to implement authentication based on MongoDB and NestJS for an Ionic application and getting the following error message after making a POST request to the route api/users:
[Nest] 85372 - 03/26/2020, 14:04:49 [ExceptionsHandler] Cannot read property 'password' of undefined +23790ms
Inside my users.schema.ts file a get the errror message:
Unexpected aliasing of 'this' to local variable.eslint(#typescript-eslint/no-this-alias)
My users.schema.ts looks like this (commented the line with the error):
import * as mongoose from 'mongoose';
import * as bcrypt from 'bcryptjs'
export const UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
unique: true,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
UserSchema.pre('save', function (next) {
const user = this; // This is marked as an error in vs code
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(this.user.password, salt, (err, hash) => {
if (err) return next();
this.user.password = hash;
next();
});
});
});
UserSchema.methods.checkPassword = (attempt, callback) => {
bcrypt.compare(attempt, this.user.password, (err, isMatch) => {
if (err) return callback(err);
callback(null, isMatch);
})
}
I tried to implement the same schema with an arrow function, but then I get the following error message after making a POST request to api/users:
[Nest] 85947 - 03/26/2020, 14:09:30 [ExceptionsHandler] Cannot read property 'isModified' of undefined +22567ms
UserSchema.pre('save', (next) => {
if (!this.user.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(this.user.password, salt, (err, hash) => {
if (err) return next();
this.user.password = hash;
next();
});
});
});
What am I doing wrong here?
You cannot use arrow functions, because you loose the track of this. Read the official documentation of arrow functions, there are some very good examples about "what is this in an array function". MDN Arrow function expressions
There are two solutions:
Remove the arrow-function callback for bcrypt
UserSchema.pre('save', function (next) {
if (!this.isModified('password')) return next();
bcrypt.genSalt(10, function (err, salt) {
if (err) return next(err);
bcrypt.hash(this.user.password, salt, (err, hash) => {
if (err) return next();
this.user.password = hash;
next();
});
});
});
Disable eslint rule and always use the user variable
UserSchema.pre('save', function (next) {
const user = this;
if (!this.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) return next();
user.password = hash;
next();
});
});
});

Q: How can I evade storing duplicated users with Sails?

I have coded a very simple sails app that just has passport authentication implemented. I use mongoDB as local database and I can't get to deny the creation of users with duplicated email. (I already have unique: true in the email attribute). Any idea what could I be missing?
var bcrypt = require('bcrypt');
module.exports = {
attributes: {
email: {
type: 'email',
required: true,
unique: true
},
password: {
type: 'string',
minLength: 6,
required: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
beforeCreate: function(user, cb) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
console.log(err);
cb(err);
} else {
user.password = hash;
cb();
}
});
});
}
};
Here I create users:
signup: function (req, res) {
User.create(req.params.all()).exec(function (err, user) {
if (err) return res.negotiate(err);
req.login(user, function (err){
if (err) return res.negotiate(err);
return res.redirect('/welcome');
});
});
}
The proper way to get errors when adding users is to check the Error object returned by the User.create() method (Promise or exec() method).
Example with Bluebird Promise :
User.create({ email : 'foo#bar.com', password : 'secret' })
.then((newUser) => {
/* do something with newly created user `newUser` */
/* eg : return res.view('user/added.ejs', newUser); */
})
.catch((err) => {
/* do something with the Error object `err` */
/* It should tell you if email already exists */
/* eg : return res.badRequest(err.message); */
});
Example with exec() method :
User.create({ email : 'foo#bar.com', password : 'secret' })
.exec((err, newUser) => {
if (err) {
/* do something with the Error object `err` */
} else {
/* do something with newly created user `newUser` */
}
});

Passport Local Strategy Login with Password

When the user tries to log in, the password that is being compared to the compare method of the Student model doesn't hash it.
For example, the value of candidatePassword is the String password the user enters which is compared to this.password, which is a hashed value of the password, thus logging, wrong password in console.
Not sure how to fix it exactly.
studentSchema.pre('save', function save(next) {
const student = this;
if (!student.isModified('password')) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(student.password, salt, (err, hash) => {
if (err) {
return next(err);
}
student.password = hash;
next();
});
});
});
ComparePassword
studentSchema.methods.comparePassword = function (candidatePassword) {
bcrypt.compareSync(candidatePassword, this.password, (err, isMatch) => {
if (err) {
return err;
}
return isMatch;
});
};
LocalStrategy
passport.use('local', new LocalStrategy({
usernameField: 'email'
}, async (email, password, done) => {
const userFound = await STUDENT
.findOne({ email: email.toLowerCase() })
.populate([ '_college', 'enrolledClasses' ]);
if (!userFound) {
console.log('User Does Not Exist');
return done(null, false, 'User Does Not Exist');
}
if (!userFound.comparePassword(password)) {
console.log('Wrong Password'); // getting this error
return done(null, false, 'Wrong Password.');
}
return done(null, userFound);
}));
Login
app.post('/auth/login', passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/login'
}));
bcrypt.compareSync does not take in the callback. It returns boolean value. So:
studentSchema.methods.comparePassword = function (candidatePassword) {
return bcrypt.compareSync(candidatePassword, this.password);
}

I have an error with passport.js implementation in Sails.js

I have a problem with Sails Passport implementation. This error appears in my terminal:
/home/tatico/sinGualichoPassport/config/passport.js:19
if (!user.validPassword(password)) {
^
TypeError: user.validPassword is not a function
at /home/tatico/sinGualichoPassport/config/passport.js:19:17
at returnResults (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:180:9)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:86:16
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:83:7
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:52:16
at Object.async.forEachOf.async.eachOf (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:236:30)
at Object.async.forEach.async.each (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:209:22)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:436:11
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:574:5
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:52:16
at Object.async.forEachOf.async.eachOf (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:236:30)
at Object.async.forEach.async.each (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:209:22)
at _buildChildOpts (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:464:9)
at _execChildOpts (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:432:8)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:81:10
at wrapper (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/lodash/index.js:3592:19)
at applyInOriginalCtx (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:421:80)
at wrappedCallback (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:324:18)
at callback.success (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/switchback/lib/normalize.js:33:31)
at _switch (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/switchback/lib/factory.js:58:28)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/adapter/dql.js:166:7
at wrapper (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/lodash/index.js:3592:19)
This is my Files:
config/passport.js:
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy
bcrypt = require('bcrypt');
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
module.exports = {
http: {
customMiddleware: function(app){
console.log('Express midleware for passport');
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(function(req,res,next){
// Set the loggedUser in locals *does it work?
// to get it from the view
res.locals.loggedUser = req.user;
next();
});
}
}
};
UserController.js
module.exports = {
auth: function(req, res) {
return res.view();
},
create: function(req, res, next) {
User.create( req.params.all(), function createdUser(err, user){
if (err) {
return res.negotiate(err);
}
req.session.authenticated = true;
req.session.user = user;
return res.json(user);
});
},
login: function(req, res, next) {
// Use Passport LocalStrategy
require('passport').authenticate('local', function(err, user, info){
if ((err) || (!user)) next(err);
req.login(user, function(err){
if (err) return res.redirect('/user/auth');
// Redirect to the user page.
return res.redirect('/user/' + user.id);
});
})(req, res);
},
logout: function(req, res){
// Call Passport method to destroy the session.
req.logout();
// Redirect to home page.
return res.redirect('/');
}
};
User.js:
module.exports = {
attributes: {
email: {
type: 'string',
required: true,
email: true,
unique: true
},
password: {
type: 'string',
required: true
},
username: {
type: 'string',
required: true,
unique: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
// Lifecycle Callbacks
beforeCreate: function(values, next) {
hashPassword(values, next);
},
beforeUpdate: function(values, next) {
if(values.password) hashPassword(values, next);
else next();
}
}
var bcrypt = require('bcrypt');
function hashPassword(values, next) {
bcrypt.hash(values.password, 10, function(err, hash) {
if (err) return next(err);
values.password = hash;
next();
});
}
Im new in Sails, and I suppose this is a not good implementantion, Anyone can Help me and give a little feed back to improve my understanding of Sails and Passport? Thanks.
ValidPassword is not defined anywhere which is leading to this error.