I was trying to implement a functionality where a user can reset a password. I have tried the below code and while I am not getting any error, its not updating the password. The password is the same ie the old password.
my User model file is as follows:-
const mongoose = require('mongoose');
var passportLocalMongoose = require("passport-local-mongoose");
const LoginUserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
// The below is used so as to allow passport to reset password
LoginUserSchema.plugin(passportLocalMongoose);
const LoginUser = mongoose.model('LoginUser', LoginUserSchema);
module.exports = LoginUser;
My routes file is as follows:-
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
var async = require("async");
// Load User model
const User = require('../models/loginuser');
var nodemailer = require("nodemailer");
var crypto = require("crypto");
// Load Auth from files
const { ensureAuthenticated, forwardAuthenticated } = require('../config/auth');
// Login Page
router.get('/login', forwardAuthenticated, (req, res) => res.render('login'));
// Register Page
router.get('/register', (req, res) =>{
if(typeof req.user == "undefined"){
console.log("HERE IT IS");
res.redirect('/users/login');
}
if (req.user.email == "theamarex#gmail.com"){
res.render('register')
}else{
res.redirect('/users/login');
}
})
// Register
router.post('/register', (req, res) => {
const { name, email, password, password2 } = req.body;
let errors = [];
if (!name || !email || !password || !password2) {
errors.push({ msg: 'Please enter all fields' });
}
if (password != password2) {
errors.push({ msg: 'Passwords do not match' });
}
if (password.length < 6) {
errors.push({ msg: 'Password must be at least 6 characters' });
}
if (errors.length > 0) {
res.render('register', {
errors,
name,
email,
password,
password2
});
} else {
User.findOne({ email: email }).then(user => {
if (user) {
errors.push({ msg: 'Email already exists' });
res.render('register', {
errors,
name,
email,
password,
password2
});
} else {
const newUser = new User({
name,
email,
password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => {
req.flash(
'success_msg',
'You are now registered and can log in'
);
res.redirect('/users/login');
})
.catch(err => console.log(err));
});
});
}
});
}
});
// Login
router.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/users/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
// Logout
router.get('/logout', (req, res) => {
req.logout();
req.flash('success_msg', 'You are logged out');
res.redirect('/users/login');
});
// Dashboard
router.get('/dashboard', ensureAuthenticated, (req, res) =>{
res.render('dashboard', {
user: req.user
})
}
);
// Forgot password url
router.get('/forgot', function(req, res) {
res.render('forgot');
});
router.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/users/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: '',
pass: ''
}
});
var mailOptions = {
//to: user.email,
to: "cechque#gmail.com",
from: 'theamarexrouting#gmail.com',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/users/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
console.log('mail sent');
req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/users/forgot');
});
});
// Reset password url
router.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('/forgot');
}
res.render('reset', {token: req.params.token});
});
});
router.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
if(req.body.password === req.body.confirm) {
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.password = req.body.password;
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) throw err;
user.password = hash;
user.save(function(err) {
req.login(user, function(err) {
console.log(user);
done(err, user);
});
});
});
});
} else {
req.flash("error", "Passwords do not match.");
return res.redirect('back');
}
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: '',
pass: ''
}
});
var mailOptions = {
to: "",
from: '',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/users/dashboard');
});
});
module.exports = router;
I am a bit confused where I have gone wrong. I tried to search various answers online and on this forum but it didn't help me out. Please help me out. Thanks
I have made changes to the code. You have used passport-local-mongoose wrongly here.
//register
if (errors.length > 0) {
res.render('register', {
errors,
name,
username,
password,
password2
});
} else {
User.findOne({ username: username }).then(user => {
if (user) {
errors.push({ msg: 'username already exists' });
res.render('register', {
errors,
name,
username,
password,
password2
});
} else {
const newUser = new User({
name,
username,
password
});
User.register(newUser, req.body.password, function(err, user){
console.log(req.body)
if(err){
console.log(err);
return res.render("register", {error: err.message});
}
passport.authenticate("local")(req, res, function(){
req.flash("success", "Successfully Signed Up! Nice to meet you " + req.body.name);
res.redirect('/users/login');
});
});
}
});
}
// forgot password
router.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ username: req.body.username }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that username address exists.');
return res.redirect('/users/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
//reset token
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
if(req.body.password === req.body.confirm) {
user.setPassword(req.body.password, function(err) {
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
})
} else {
req.flash("error", "Passwords do not match.");
return res.redirect('back');
}
});
},
I got a changepassword route using passport. Maybe its useful for you. Here it is:
router.post('/changepassword', passport.authenticate('jwt', { session: false }), (req, res) => {
User.findOne({ username: req.user.username })
.then(user => {
if (!user) {
return res.status(404).json({
success: false
});
} else if (req.body.password !== req.body.confirm_password) {
return res.status(404).json({
msg: "Wachtwoorden komen niet overeen",
success: false
});
}
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(req.body.password, salt, (err, hash) => {
user.password = hash;
user.save().then(user => {
return res.status(201).json({
success: true,
msg: "Wachtwoord veranderd"
});
})
});
});
})
.catch(err => {
console.log(err)
})
})
Related
I'm using Passport js local strategy but I can't redirect from my admin page. it always fails even if the login and password are correct, below is the auth.js and login.js code
login.js
router.get('/', (req, res, next) =>{
if (req.query.fail){
res.render('admin/login', {layout: 'admin.hbs', message: "Usuario e/ou Senha invalidos"});
}else{
res.render('admin/login', {layout: 'admin.hbs', message: null});
}
})
router.post('/',
passport.authenticate('local', { failureRedirect: '/login?fail=true' }),
function(req, res) {
res.redirect('/admin');
});
auth.js
const users = [{
_id: 123,
username: "adm",
password: hashedPassword
}];
console.log(users);
module.exports = function(passport){
function findUser(username){
return users.find(item => item.username === username);
}
function findUserById(id){
return users.find(item => item._id === id);
}
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
try {
const user = findUserById(id);
done(null, user);
} catch (err) {
console.log(err);
return done(err, null)
}
});
passport.use(new localStrategy({
usernameField: 'username',
passwordField: 'password',
},
(username, password, done) => {
try{
const user = findUser(username).then(user);
if(!user) return done(null, false);
const isValid = bcrypt.compare(password, user.password);
if(!isValid) return done(null, false);
return done(null, user);
}
catch(err){
console.log(err);
return done(err, false)
}}));
}
I don't know why it's not working, I wanted help getting into the admin page
I'm havig trouble understanding how to access the properties of a global variable that is set in the middleware of my application
// app.js
app.use(function (req, res, next) {
res.locals.user = req.user || null;
next();
});
I would have thought I could access the req.user.username in my template (using handlebars), but for some reason it is forcing me to iterate over this object.
A consle.log(req.user) shows:
_id: 5f01f9a861f5b33b42a9e,
username: 'onetap',
email: 'test#gmail.com',
password: '$2b$10$VLBS8ZwPKiaXasdfsiiwfg.wyJ1J5CwTKLjS5zXwAsvukHpNmk0HG2',
createdAt: 2020-07-05T16:02:48.081Z,
__v: 0
}
And in my template I have to use an each loop and can't access the properties directly. the req.user is not an array either.
{{user.username}}//undefined
{{#each user}}
{{username}} //onetap
{{/each}}
passport.js file
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const mongoose = require("mongoose");
// Load User Model
const User = require("../models/User");
module.exports = function (passport) {
passport.use(
new LocalStrategy({ username: "username" }, (username, password, done) => {
// Match User
User.findOne({
username: username,
}).then((user) => {
if (!user) {
return done(null, false, { message: "Invalid Username" });
}
console.log("Checking password");
// Match password
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Password incorrect" });
}
});
});
})
);
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
};
I was able to fix this by chaning deserialize to:
passport.deserializeUser(function (id, done) {
User.findById(id)
.lean()
.exec(function (err, user) {
done(err, user);
});
});
why is the console output is always found? any email or passwords i enter, the output is the same, even if they are not in the database
app.post("/login", (req, res) => {
const email = req.body.username
const password = req.body.password
User.find({ email: email, password: password }, function(err, userInfo) {
if (err) {
console.log("err")
} else {
if (userInfo) {
console.log("found")
} else {
console.log("not found")
}
}
});
})
Because User.find will return an array, even if there is no document matching your query it will return an empty array.
And in javascript, if you pass empty array in if the condition it passes
Use User.findOne or check if (userInfo.length > 0)
app.post("/login", (req, res) => {
const email = req.body.username
const password = req.body.password
User.findOne({ email: email, password: password }, function(err, userInfo) {
if (err) {
console.log("err")
} else {
if (userInfo) {
console.log("found")
} else {
console.log("not found")
}
}
});
})
passport.use('local.signup', new Localstrategy({
usernameField: 'email',
passwordField: 'password',
roleField: 'role',
passReqToCallback: true
}, function(req, email, password, role, done) {
req.checkBody('email', 'Invalid Email').notEmpty().isEmail();
req.checkBody('password', 'Invalid Password ').notEmpty().isLength({min:4});
req.checkBody('role', 'Invalid Password').notEmpty();
var errors = req.validationErrors();
if (errors) {
var messages = [];
errors.forEach(function(error) {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
// what the...
User.findOne({
'email': email
}, function(err, user) {
if (err) {
return done(err);
}
if (user) {
return done(null, false, {
message: 'Email is already in use.'
});
}
var newUser = new User();
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
newUser.role = role;
newUser.save(function(err, result) {
if (err) {
return done(err);
}
return done(null, newUser);
});
});
}));
I don't believe this setting will do anything:
roleField: 'role',
You can fix the error by changing your function arguments from this:
function(req, email, password, role, done) {
to this:
function(req, email, password, done) {
I am using Mongo in my app, I have a db named test, what I am doing now is just an app to understand the workflow among Angular, Nodejs and Mongo.
The issue I have right now, or actually I don't know if this an issue but, I created an user with the name of User1 and a given email address, then I went to the app and saved some stuff, I logged out and then logged in again to confirm that the info I saved was there, and YES! the info was there it doesn't matter how many times and logged in and logged out.
Then I created another user with the name of User2 and obviously a different email address, but when I logged in, the information I had save from User1 was there.
I am on a local environment:
Node version: 5.0.0
MongoDB shell version: 3.2.0
this is what I have regarding the user schema
var userSchema = new mongoose.Schema({
name: { type: String, trim: true, required: true },
email: { type: String, unique: true, lowercase: true, trim: true },
password: String,
facebook: {
id: String,
email: String
},
google: {
id: String,
email: String
}
});
userSchema.pre('save', function(next) {
var user = this;
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
var User = mongoose.model('User', userSchema);
mongoose.connect('localhost');
and here in Nodejs the signup route
app.post('/auth/signup', function(req, res, next) {
var user = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});
user.save(function(err) {
if (err) return next(err);
res.sendStatus(200);
});
});
and the service un Angular
signup: function(user) {
return $http.post('/auth/signup', user)
.success(function() {
$location.path('/login');
});
}
the signup controller
.controller('SignupCtrl', function($scope, Auth) {
$scope.signup = function() {
Auth.signup({
name: $scope.displayName,
email: $scope.email,
password: $scope.password
});
};
Here is the logging part:
Node:
app.post('/auth/login', function(req, res, next) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) return res.status(401).send('User does not exist');
user.comparePassword(req.body.password, function(err, isMatch) {
if (!isMatch) return res.status(401).send('Invalid email and/or password');
var token = createJwtToken(user);
res.send({ token: token });
});
});
});
Angular Service
login: function(user) {
return $http.post('/auth/login', user).success(function(data) {
$window.localStorage.token = data.token;
var payload = JSON.parse($window.atob(data.token.split('.')[1]));
$rootScope.currentUser = payload.user;
$location.path('/');
})
}
Controller
.controller('LoginCtrl', function($scope, Auth) {
$scope.login = function() {
Auth.login({ email: $scope.email, password: $scope.password });
};
Update
var tokenSecret = 'whatever goes here';
function ensureAuthenticated(req, res, next) {
if (req.headers.authorization) {
var token = req.headers.authorization.split(' ')[1];
try {
var decoded = jwt.decode(token, tokenSecret);
if (decoded.exp <= Date.now()) {
res.status(400).send('Access token has expired');
} else {
req.user = decoded.user;
return next();
}
} catch (err) {
return res.status(500).send('Error parsing token');
}
} else {
return res.sendStatus(401);
}
}
function createJwtToken(user) {
var payload = {
user: user,
iat: new Date().getTime(),
exp: moment().add(7, 'days').valueOf()
};
return jwt.encode(payload, tokenSecret);
}
I created this Gist with the full code
Here is the Github repository with all of the info
what do you think its happening?