hash the password in the routes file and update - express

This is PUT method I want to hash my password(using passport) & and update it.
router.put('/reset/:token', function(req, res) {
console.log('listening');
User.findOneAndUpdate({resetPasswordToken:req.params.token},{
password: req.body.password,
resetPasswordToken: undefined,
resetPasswordExpires: undefined
},function(err,user) {
if(err) {
console.log(err + 'is here');
} else {
res.json(user);
}
});
});
I want to hast the variable only password.How can I hash within this method & then update it.

I'm assuming you are using Mongoose. First, create a pre method inside your Schema.
UserSchema
const mongoose = require('mongoose')
, bcrypt = require('bcrypt-nodejs')
, SALT_WORK_FACTOR = 10;
const UserSchema = new mongoose.Schema({
... // schema here
});
/**
* Hash password with blowfish algorithm (bcrypt) before saving it in to the database
*/
UserSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password'))
return next();
user.password = bcrypt.hashSync(user.password, bcrypt.genSaltSync(SALT_WORK_FACTOR), null);
next();
});
mongoose.model('User', UserSchema);
And then in your route:
router.put('/reset/:token', function(req, res, next) {
User.findOne({resetPasswordToken: new RegExp('^' + req.params.token + '$', "i")}, 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.save().then(function (user) {
return res.status(200).json(user);
});
});
});

Related

Router export failing while exporting multiple functions (TypeError: app.use() requires a middleware function)

I'm having this odd error and I'm not knowing what to do to make it work. The thing is, I need to export some functions and express router. The thing is, if I try to set
module.exports = {router, function1, function2}
it gaves me that error
(TypeError: app.use() requires a middleware function).
If I try to set my functions with exports.function1 = async function function1 (req,res) {blablabla} they get exported but I still get the same error... I need to use the functions in this way
router.get('/api/auth0/users', async (req, res,next) => {
function1(res, next)
})
and I'm lacking ideas... and have no clue of why the multiple module.exports it's not working since I've used it a lot (seems like the problem is with the router.... (NOTE: I've just used an example code since mine is a 140 lines src)
(NOTE2: function1 and function2 are async since they make queries to MongoDB)
UPDATE: (Adding the import codes)
I import it in my main .js file like this
const {router} = require('./auth/auth0')
then tell app to use it like this
app.use(router);
app is defined using this lines
const express = require("express");
const app = express();
changing the export/import name to another like authRouter or something makes no difference.
Heres the complete code:
const router = require('express').Router()
const express = require('express')
const passport = require('passport');
const session = require('express-session')
const {generateJwt} = require("../helpers/generateJwt");
const usuarios = require('../models/usuarios')
let OpenIDConnectStrategy = require('passport-openidconnect');
passport.serializeUser(function (user, cb) {
cb(null, user);
});
passport.deserializeUser(function (obj, cb) {
cb(null, obj);
});
passport.use(new OpenIDConnectStrategy({
issuer: 'https://' + process.env.AUTH0_DOMAIN + '/',
authorizationURL: 'https://' + process.env.AUTH0_DOMAIN + '/authorize',
tokenURL: 'https://' + process.env.AUTH0_DOMAIN + '/oauth/token',
userInfoURL: 'https://' + process.env.AUTH0_DOMAIN + '/userinfo',
clientID: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
callbackURL: '/login/callback',
scope: [ 'profile', 'email' ]
},
function verify(issuer, profile, cb) {
if(profile){
userEmail = profile.emails[0].value
userProfile = profile
whoIs = profile.id
}
return cb(null,profile)
}
));
router.use(express.json())
router.use(session({ secret: 'keyboard cat~troubles', secured:true, key: 'sid', saveUninitialized: true, resave: false}));
router.use(passport.initialize())
router.use(passport.session())
var userProfile = ""
let userEmail = ""
let whoIs = ""
let token = ""
async function createUser(res,next) {
try {
token = await generateJwt(whoIs, process.env.JWT_SECRET_KEY);
const nAccount = new usuarios({
nombre: userProfile.name.givenName,
apellido: userProfile.name.familyName,
auth0Id: whoIs,
email: userEmail,
token: token
});
await nAccount.save()
return res.status(201).json({Status: "Cuenta creada exitosamente", token: token});
} catch (error) {
console.log(error)
return res.redirect('/api/auth0/logged')
}
}
async function findUser(res, next){
try{
let email = userEmail
let mailEncontrado = await usuarios.findOne( {email} )
if (!mailEncontrado ){
return res.redirect('/api/auth0/register')
}
else {
token = await generateJwt(whoIs, process.env.JWT_SECRET_KEY);
let userID = await usuarios.findOneAndUpdate(
{email},
{ nombreAuth0: userProfile.name.givenName,
apellidoAuth0: userProfile.name.familyName,
auth0Id: whoIs,
token: token},
{ new: true }
)
return res.redirect('/api/auth0/logged')
}
}
catch (err) {
console.log(err)
}
}
async function userAuthenticated(res, next) {
if( req.isAuthenticated() === true){
console.log(req.isAuthenticated())
return true
} else{
console.log(req.isAuthenticated())
return false
}
}
router.get('/api/auth0/login', passport.authenticate('openidconnect',{prompt: 'login', failureMessage: true}));
router.get('/api/auth0/users', async (req, res,next) => {
findUser(res, next)
})
router.get('/api/auth0/register', async (req, res,next) => {
createUser(res, next)
})
router.get('/login/callback', passport.authenticate('openidconnect', {
successRedirect: '/api/auth0/users',
failureRedirect: '/api/auth0/login'
}));
router.get('/api/auth0/logged', (req, res) => {
if(whoIs === ""){
return res.status(401).json('Error de autenticacion')
}
else {
console.log(whoIs)
return res.status(201).json({Status: 'Usuario logueado. ID = '+ whoIs, Token: token, Email: userEmail})
}
})
router.get('/api/auth0/logout', (req, res) => {
if(!req.user){
res.json("No hay usuario autenticado")
}
req.logout()
res.status(201).json("Sesion finalizada exitosamente.")
})
module.exports = {router, userAuthenticated}

How to use async and await with Express and MongoDB

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const mongodb = require('mongodb');
const app = express();
app.use(cors())
app.use(bodyParser.json());
const MongoClient = mongodb.MongoClient;
const url = "mongodb://localhost:27017/recart";
app.post("/register" , (req, res) => {
const { displayName, email, password } = req.body;
if (!email || !displayName || !password) {
return {code: 400, msg: "incorrect form submission"}
}
let insertedid = null
MongoClient.connect(url, (err, db) => {
if (err) throw err;
var dbo = db.db("recart");
var myobj = { displayName: displayName, email: email, password: password };
dbo.collection("customers").insertOne(myobj)
.then(res => {
insertedid = res.insertedId
})
});
res.json({id: insertedid})
})
app.listen(process.env.PORT || 3000, ()=> {
console.log(`App is running on port 3000`);
})
Here, I am storing data inside db and sending the last inserted id
to the frontend.
However, id is returning null.
How can I use async and await to solve this issue?
You can modify your post function using async await like this:
app.post("/register", async (req, res) => {
const { displayName, email, password } = req.body;
if (!email || !displayName || !password) {
return {code: 400, msg: "incorrect form submission"}
}
let insertedid = null ;
MongoClient.connect(url,{ useNewUrlParser: true }, async (err, db) => {
if (err) throw err;
var dbo = db.db("recart");
var myobj = { displayName: displayName, email: email, password: password };
var result = await dbo.collection("customers").insertOne(myobj);
insertedid = result.insertedId;
res.json({ id: insertedid})
});
})

user.setPassword is not a function - passport local mongoose

I am implementing a reset password feature on for the users of my website. However, it seems to throw this error when the user confirms new password at the reset.ejs page.
The following steps are being performed correctly:
Token sent on mail
When clicked on token, new password page opens
When user enters new password and confirm new password and hits the button to save the new password, the function in users.js user.setPassword does not work as the error is mentioned below. It is a built in function of passport-local-mongoose.
ERROR: user.savePassword is not a function
Including all the code files below:
users.js:
var express = require('express');
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: './uploads'});
var passport = require('passport');
var mongoose = require('mongoose');
var LocalStrategy = require('passport-local').Strategy;
var randomstring = require("randomstring");
var User = require('../models/user');
var data=require('../models/data');
var checklist=require("../models/checklist");
var async = require("async");
var crypto = require("crypto");
var passportLocalMongoose=require("passport-local-mongoose");
// "use strict";
const nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register/:type', function(req, res, next) {
res.render('user/register.ejs',{title:'Register',type:req.params.type});
});
router.get('/login', function(req, res, next) {
res.render('user/login.ejs', {title:'Login'});
});
router.post('/login',
passport.authenticate('local',{failureRedirect:'/users/login', failureFlash: 'Invalid username or password'}),
function(req, res) {
var previouspath=req.cookies.previouspath;
if(req.cookies.checklist==undefined){
req.flash('success', 'You are now logged in');
if(req.user.as=='seller'){
if(previouspath!=undefined){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer');
}
else
res.redirect('/buyer');
}
else {
if(previouspath!=undefined){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer');
}
else
res.redirect('/buyer');
}
}
else{
var ids=req.cookies.checklist['data']
var checks=[];
for(var i=0;i<ids.length;i++){
checks.push({user:req.user,data:ids[i]});
}
checklist.insertMany(checks,function(err, d) {
if(err)console.log(err);
res.clearCookie('checklist');
req.flash('success', 'You are now logged in');
if(req.user.as=='seller'){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/seller')
}
else {
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer')
}
});
}
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(function(username, password, done){
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) return done(err);
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message:'Invalid Password'});
}
});
});
}));
router.post('/register/:type',function(req, res, next) {
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var institution=req.body.institution;
var education=req.body.education;
var proffession=req.body.proffession;
var country=req.body.country;
//check if email does not already exists
//check if username does not already exists
User.find({ $or: [ { email: { $eq: req.body.email } }, { username: { $eq: req.body.username } } ] },function(err,data){
if(err)console.log(err);
if(data.length!=0){
console.log(data.length);
req.flash('success','email or username is repeated.');
res.redirect('/users/register/'+req.params.type);
}
else
{
var password = req.body.password;
var password2 = req.body.password2;
var as =req.params.type;
// Form Validator
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email is not valid').isEmail();
req.checkBody('username','Username field is required').notEmpty();
req.checkBody('password','Password field is required').notEmpty();
// Check Errors
var errors = req.validationErrors();
if(errors){
res.render('user/register.ejs', {
errors: errors
});
} else{
var newUser = new User({
name: name,
email: email,
username: username,
password: password,
as :as,
institution:institution,
education:education,
proffession:proffession,
country:country
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
// res.location('/');
var token=randomstring.generate(7);
var to=req.body.email;
var subject='Email Confirmation from dataSeed ';
var message='<h1>Use this code to register </h1><p>Your verification Code is: <h2>'+token+'</h2></p>';
var mailOptions=sendmail(to,subject,message);
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
}
else
{
res.render('user/emailconfirmation.ejs',{username:req.body.username,token:token});
}
});
}
}
});
function sendmail(to,subject,message){
var mailOptions = {
from: 'dataseedltd#gmail.com',
to: to,
subject: subject,
html: message
};
return mailOptions;
}
router.post('/emailconfirmation/:token',function(req, res) {
if(req.params.token==req.body.token){
req.flash('success', 'You are now registered and can login');
res.redirect('/');
}
else{
User.remove({username:req.body.username},function(err,data){
if(err)console.log(err);
res.redirect('/');
});
}
});
});
router.get('/logout', function(req, res){
req.logout();
req.flash('success', 'You are now logged out');
res.redirect('/users/login');
});
//Forgot Password
router.get('/forgot',function(req,res){
res.render("forgotpassword.ejs");
});
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('success', '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: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'dataseedltd#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');
});
});
router.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('success', 'Password reset token is invalid or has expired.');
return res.redirect('/users/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.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');
}
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'dataseedltd#gmail.com',
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('/login');
});
});
module.exports = router;
users.js (model):
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var passportLocalMongoose=require("passport-local-mongoose");
mongoose.connect('mongodb://localhost/dataseed');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
},
as:{
type:String
},
institution:{
type:String
},
education:{
type:String
},
proffession:{
type:String
},
country:{
type:String
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
callback(null, isMatch);
});
}
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
It seems like you don't have a method called setPassword defined under user model. This is mainly because you haven't plugin the passport-local-mongoose to UserSchema. Add UserSchema.plugin(passportLocalMongoose); before creating the model from UserSchema. like this
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var passportLocalMongoose=require("passport-local-mongoose");
mongoose.connect('mongodb://localhost/dataseed');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
},
as:{
type:String
},
institution:{
type:String
},
education:{
type:String
},
proffession:{
type:String
},
country:{
type:String
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
UserSchema.plugin(passportLocalMongoose);
var User = module.exports = mongoose.model('User', UserSchema);

ForbiddenError: invalid csrf token

I am trying to use csrf in add employee function. However, whenever I hit submit I alway get ForbiddenError: invalid csrf token. I am not sure the way I did csrf correctly.
On the other hand, I have a login and register form. It works fine. And I did the same steps for add employee.
I've been reading some other posts but I didn't understand them. Can anyone point me to the correct way? I am really appreciate.
const express = require('express');
const router = express.Router();
const {uploadProduct, uploadForEmployee, uploadForVendor} = require('../upload');
const validation = require('validator');
const bcrypt = require('bcryptjs');
const csrf = require('csurf');
const csrfProtection = csrf();
//Load User model
const User = require('../../models/User');
router.get('/viewEmployee', (req, res) => {
User.find({$or: [{role: 'Admin'}, {role: 'Employee'}] }, (err, doc) => {
res.status(200).render('./admin/viewEmployee', {
user: req.user,
doc: doc,
link: "/admin/employees/"
})
})
});
router.delete('/:email', (req, res) => {
User.deleteOne({email: req.params.email}, (err, user) => {
if(err) {
console.log('Error while deleting product');
} else {
console.log(req.params.email + ' deleted');
res.redirect('/admin/employees/viewEmployee');
}
});
});
router.use(csrfProtection);
router.get('/addEmployee', (req, res) => {
res.render("./admin/employeeForm", {csrfToken: req.csrfToken()});
});
router.post('/addEmployee', uploadForEmployee.single('image'), (req, res) => {
let {name, email, password, phone, address, role} = req.body;
let image = req.file;
let errors = [];
if(!name || !email || ! password || !phone || !address || !role) {
errors.push({msg: 'Please enter all fields.'});
}
if(!image) {
errors.push({msg: 'Please upload a photo of yourself.'});
}
//sanitize input
name = validation.escape(name);
email = validation.escape(email);
password = validation.escape(password);
phone = validation.escape(phone);
address = validation.escape(address);
//Validate email
if(!validation.isEmail(email)){
errors.push({msg: 'Bad email.'})
} else {
email = validation.normalizeEmail(email, [
'all_lowercase', 'gmail_remove_dots','gmail_remove_subaddress', 'gmail_convert_googlemaildotcom',
'outlookdotcom_remove_subaddress', 'yahoo_remove_subaddress', 'icloud_remove_subaddress'
])
}
if (password.length < 6) {
errors.push({ msg: 'Password must be at least 6 characters.' });
}
if (errors.length > 0) {
res.render('./admin/employeeForm', {
errors,
name,
email,
password,
phone,
address,
role,
image,
csrfToken: req.csrfToken()
});
} else {
User.findOne({ email: email }).then(user => {
if (user) {
errors.push({ msg: 'Email already exists.' });
res.render('./admin/employeeForm', {
errors,
name,
email,
password,
phone,
address,
role,
image,
csrfToken: req.csrfToken()
});
} else {
const newUser = new User({
name: name,
email: email,
password: password,
phone: phone,
address: address,
role: role,
imageUrl: '/images/employees/' + image.filename
});
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('/admin/employees/viewEmployee');
})
.catch(err => console.log(err));
});
});
}
});
}
});
module.exports = router;
This is my login and register functions. These ones worked with csrf just fine.
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
const {ensureLoggedIn, ensureLoggedOut} = require('connect-ensure-login');
const validation = require('validator');
const csrf = require('csurf');
const csrfProtection = csrf();
// Load User model
const User = require('../models/User');
//Profile
router.get('/profile', ensureLoggedIn('/users/login'), (req, res, next) => {
res.render('profile')
});
// Logout
router.get('/logout', (req, res) => {
req.logout();
req.flash('success_msg', 'You are logged out.');
res.redirect('/users/login');
});
// Register
router.post('/register', (req, res) => {
let { name, email, password, password2 } = req.body;
let errors = [];
if (!name || !email || !password || !password2) {
errors.push({ msg: 'Please enter all fields' });
}
//sanitize input
name = validation.escape(name);
email = validation.escape(email);
password = validation.escape(password);
password2 = validation.escape(password2);
//Validate email
if(!validation.isEmail(email)){
errors.push({msg: 'Bad email.'})
} else {
email = validation.normalizeEmail(email, [
'all_lowercase', 'gmail_remove_dots','gmail_remove_subaddress', 'gmail_convert_googlemaildotcom',
'outlookdotcom_remove_subaddress', 'yahoo_remove_subaddress', 'icloud_remove_subaddress'
])
}
if (password != password2) {
errors.push({ msg: 'Invalid Password.' });
}
if (password.length < 6) {
errors.push({ msg: 'Password must be at least 6 characters.' });
}
if (errors.length > 0) {
res.render('./home/register', {
errors,
name,
email,
password,
password2,
csrfToken: req.csrfToken()
});
} else {
User.findOne({ email: email }).then(user => {
if (user) {
errors.push({ msg: 'Email already exists.' });
res.render('./home/register', {
errors,
name,
email,
password,
password2,
csrfToken: req.csrfToken()
});
} 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', {
successReturnToOrRedirect: '/',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
router.use(csrfProtection);
// Login Page
router.get('/login', ensureLoggedOut('/'), (req, res, next) => {
res.render('./home/login', {
csrfToken: req.csrfToken()
})
});
// Register Page
router.get('/register', ensureLoggedOut('/'), (req, res, next) => {
res.render('./home/register', {
csrfToken: req.csrfToken()
})
});
module.exports = router;

Implement Remember Me functionality in Express + PassportJS + Redis app

I'm trying to build authentication system with ExpressJS and PassportJS. For session store I use Redis. I wanna use Remember Me. Every time when the user signs in and has marked "remember me" check-box, it should automatically sign in by next visit on site. I have downloaded an example app form Github https://github.com/jaredhanson/passport-remember-me and change for my using.
var express = require('express')
, passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, mongodb = require('mongodb')
, mongoose = require('mongoose')
, bcrypt = require('bcrypt')
, SALT_WORK_FACTOR = 10
, RedisStore = require('connect-redis')(express);
mongoose.connect('localhost', 'test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
console.log('Connected to DB');
});
// User Schema
var userSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true},
accessToken: { type: String } // Used for Remember Me
});
// Bcrypt middleware
userSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, 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();
});
});
});
// Password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if(err) return cb(err);
cb(null, isMatch);
});
};
// Remember Me implementation helper method
userSchema.methods.generateRandomToken = function () {
var user = this,
chars = "_!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
token = new Date().getTime() + '_';
for ( var x = 0; x < 16; x++ ) {
var i = Math.floor( Math.random() * 62 );
token += chars.charAt( i );
}
return token;
};
// Seed a user
var User = mongoose.model('User', userSchema);
var usr = new User({ username: 'bob', email: 'bob#example.com', password: 'secret' });
usr.save(function(err) {
if(err) {
console.log(err);
} else {
console.log('user: ' + usr.username + " saved.");
}
});
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing.
//
// Both serializer and deserializer edited for Remember Me functionality
passport.serializeUser(function(user, done) {
var createAccessToken = function () {
var token = user.generateRandomToken();
User.findOne( { accessToken: token }, function (err, existingUser) {
if (err) { return done( err ); }
if (existingUser) {
createAccessToken(); // Run the function again - the token has to be unique!
} else {
user.set('accessToken', token);
user.save( function (err) {
if (err) return done(err);
return done(null, user.get('accessToken'));
})
}
});
};
if ( user._id ) {
createAccessToken();
}
});
passport.deserializeUser(function(token, done) {
User.findOne( {accessToken: token } , function (err, user) {
done(err, user);
});
});
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object. In the real world, this would query a database;
// however, in this example we are using a baked-in set of users.
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: 'Unknown user ' + username }); }
user.comparePassword(password, function(err, isMatch) {
if (err) return done(err);
if(isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
var app = express();
// configure Express
app.configure(function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.engine('ejs', require('ejs-locals'));
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({
store: new RedisStore({ host: '127.0.0.1', port: 6379, prefix: 'chs-sess' }),
secret: '4Md97L1bL4r42SPn7076j1FwZvAiqube',
maxAge: new Date(Date.now() + 3600000)
}));
// Remember Me middleware
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/login' ) {
if ( req.body.rememberme ) {
req.session.cookie.maxAge = 2592000000; // 30*24*60*60*1000 Rememeber 'me' for 30 days
} else {
req.session.cookie.expires = false;
}
}
next();
});
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(__dirname + '/../../public'));
});
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
app.get('/login', function(req, res){
res.render('login', { user: req.user, message: req.session.messages });
});
// POST /login
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
//
// curl -v -d "username=bob&password=secret" http://127.0.0.1:3000/login
//
/***** This version has a problem with flash messages
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/');
});
*/
// POST /login
// This is an alternative implementation that uses a custom callback to
// acheive the same functionality.
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
req.session.messages = [info.message];
return res.redirect('/login')
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.listen(3000, function() {
console.log('Express server listening on port 3000');
});
// Simple route middleware to ensure user is authenticated.
// Use this route middleware on any resource that needs to be protected. If
// the request is authenticated (typically via a persistent login session),
// the request will proceed. Otherwise, the user will be redirected to the
// login page.
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
My app doesn't work with Remember Me, every time when I close the browser, I have to sign-in again. I don't know, what I have done wrong.
My second question is, how doe Remember Me works as usual? I have some idea but not exactly sure.