Can't set headers after they are sent node js - javascript

I'm trying to send some form data, but I get this error using express.js:
Can't set headers after they are sent.
This is my code so far:
app.post('/api/users/profile/:username', isAuthenticated, userUploads, function(req, res, next) {
if (req.params.username) {
User.findOne({ username: req.params.username }, function(err, user) {
if (err) return next(err);
user.profile.name = req.body.name;
user.profile.gender = req.body.gender;
var files = req.files.file;
if (files){
if (files.length > 0){
for (f in files){
user.profile.pictures.push(files[f])
}
}else{
user.profile.pictures.push(files)
}
}
user.save(function(err) {
if (err) return next(err);
res.send(200);
});
console.log(res.send(user)) //HERE IS WHERE I GET THE ERROR
});
}else{
return res.send(400, { message: 'User does not exist!!' });
}
});

By console logging res.send(user) you are sending again. You can send once and once only.
app.post('/api/users/profile/:username', isAuthenticated, userUploads, function(req, res, next) {
if (req.params.username) {
User.findOne({ username: req.params.username }, function(err, user) {
if (err) return next(err);
user.profile.name = req.body.name;
user.profile.gender = req.body.gender;
var files = req.files.file;
if (files){
if (files.length > 0){
for (f in files){
user.profile.pictures.push(files[f])
}
}else{
user.profile.pictures.push(files)
}
}
user.save(function(err) {
if (err) return next(err);
res.status(200).send(user);
});
});
}else{
return res.send(400, { message: 'User does not exist!!' });
}
});

Related

Node JS Express, Passport JS, and Android Device Authentication Issues

I am currently implementing a login page via Node JS Express and Passport using Passport's local strategy: http://www.passportjs.org/packages/passport-local/.
The database is using MongoDB.
The problem that is occurring is I am unable to login successfully (sometimes I can, but it is not consistent) on an android phone and android tablet with User A.
The response being returned is a 401 (unauthorized error).
I have verified that I can log in successfully consistently with User A from a desktop computer, and also verified I can login on iOS devices (iPhone and iPad).
Does anyone have any suggestions, and / or know what the issue is?
Below is the code that executes the authentication
app_api/config/passport.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User');
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(username, password, done) {
User.findOne({ email: 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);
});
}
));
app_api/controllers/authentication.js
var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var sendJSONresponse = function(res, status, content) {
res.status(status);
res.json(content);
};
module.exports.test = function(req, res) {
sendJSONresponse(res, 200, { 'status' : 'success' });
};
module.exports.register = function(req, res) {
if(!req.body.name || !req.body.email || !req.body.password) {
sendJSONresponse(res, 400, {
"message": "All fields required"
});
return;
}
var user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.setPassword(req.body.password);
user.setShowResume(false);
user.save(function(err) {
var token;
if (err) {
sendJSONresponse(res, 404, err);
} else {
token = user.generateJwt();
sendJSONresponse(res, 200, {
'token' : token
});
}
});
};
module.exports.login = function(req, res) {
if(!req.body.email || !req.body.password) {
sendJSONresponse(res, 400, {
'message': 'All fields required'
});
return;
}
passport.authenticate('local', function(err, user, info){
var token, showResume;
if (err) {
sendJSONresponse(res, 404, err);
return;
}
if(user){
token = user.generateJwt();
showResume = user.showResume;
sendJSONresponse(res, 200, {
'token' : token,
'showresume': showResume
});
} else {
sendJSONresponse(res, 401, info);
}
})(req, res);
};
module.exports.logout = function(req, res) {
req.logout();
res.redirect('/');
};
Below is the controller app_server/controllers/index.js and the function logincontinue which calls the app_api/controllers/authentication.js file and its function login:
app_server/controllers/index.js
var request = require('request');
var apiOptions = {
server : "http://localhost:3000"
};
if (process.env.NODE_ENV === 'production') {
apiOptions.server = "https://siteDomain.com";
}
module.exports.home = function(req, res) {
renderLoginPage(req, res);
};
/* Other routes / functions ... */
module.exports.logincontinue = function(req, res) {
var path = '/api/authentication/login', sess;
//var connectSid = res.req.cookies['connect.sid'];
var requestOptions = {
url : apiOptions.server + path,
method : "POST",
json : { email: req.body.username, password: req.body.password }/*,
headers : { 'set-cookie': connectSid }*/
};
request(requestOptions, function(err, response, body) {
if(err) {
renderPage(req, res, 'siteDomain.com', 'loginerror');
} else if(response.statusCode === 200) {
switch(body.showresume) {
case true:
res.render('loginsuccessresume', { title: 'siteDomain.com', page: 'loginsuccessresume', showresume: true });
break;
default:
renderPage(req, res, 'siteDomain.com', 'loginsuccess');
break;
}
} else if(response.statusCode === 401) {
res.render('loginunauthorized', { title: 'siteDomain.com', page: 'loginunauthorized', errormessage: body.message });
} else {
renderPage(req, res, 'siteDomain.com', 'loginerror');
}
});
};
var renderPage = function(req, res, titleValue, pageValue) {
res.render(pageValue, { title: titleValue, page: pageValue });
};
var renderLoginPage = function(req, res) {
res.render('index', { title: 'siteDomain.com', page: 'login' });
};
As an update, this issue has been resolved.
The issue was related to case-sensitivity with respect to the username field.
Changing req.body.username to req.body.username.toLowerCase() resolved the issue within app_server/controllers/index.js and the function logincontinue.
Thank you.

How to Pass Credentials to passport.authenticate?

I'm trying to secure an API endpoint on a node.js express app that uses passport.
This is my route:
router.post('/api/devices', authController.isAuthorized, catchErrors(deviceController.getDevicesAPI));
This is my authorization method:
exports.isAuthorized = (req, res, next) => {
passport.authenticate('local', {session: false}, (err, user, info) => {
if (err || !user) {
return res.json({ message: 'Something is not right ', err, info });
}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(err);
}
next();
});
})(req, res);
};
From Postman or a separate local server, I get the response:
{
"message": "Something is not right ",
"err": null,
"info": {
"message": "Missing credentials"
}
}
This is the Postman configuration:
What am I missing?
How is your local strategy configured? It seems like a database query problem
As the sample in http://www.passportjs.org/docs/username-password/, please see my comments below
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) { //<--- Here is where you pass the UN&PASS
User.findOne({ username: username }, function(err, user) { //<--- Here is the sample code that should find you a user
if (err) { return done(err); } //<--- Here could be where the response is coming from
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user); //<--- Here is the sample code that should let you return that user
});
}
));
I finally dug it out from here. User.authenticate() is the method I was looking for.
exports.isAuthorized = async (req, res, next) => {
const username = req.body.username;
const password = req.body.password;
const user = await User.findOne({ email: username });
if (!user) {
res.sendStatus(403);
return;
}
user.authenticate(password, function(err, result) {
if (result) {
next();
return;
}
res.sendStatus(403);
});
};

Reset password function with bcrypt does not work, Cannot set headers after they are sent to the client?

So i made a reset password function and it looks like this:
router.get('/reset/:id',function(req,res,next){
User.findOne({'resetToken': req.params.id.trim()})
.exec(function(error, user){
if (error) return next(error);
else if(!user){
var err = new Error('Invalid Reset Link! The system is unable to find a user with the given reset code.');
err.status = 401;
return next(err);
}else return res.render('resetpass',{token: req.params.id});
})
})
router.post('/reset/:id', function(req,res,next){
if(req.body.newPassword === req.body.confirmNewPassword)
User.findOne({'resetToken': req.params.id.trim()},function(error,user){
if(error) return next(error);
bcrypt.hash(req.body.password, 5, function(err, hash) {
if (err) {
return next(err);
}
user.password = hash;
user.resetToken ='';
user.save();
})
});
return res.redirect('/login');
})
so when i complete the reset password fields and click submit i get this in console : Cannot set headers after they are sent to the client
and if i use this:
router.post('/reset/:id', function(req,res,next){
if(req.body.newPassword === req.body.confirmNewPassword)
var cp;
User.findOne({'resetToken': req.params.id.trim()},function(error,user){
if(error) return next(error);
bcrypt.hash(req.body.password, 5, function(err, hash) {
if (err) {
return next(err);
}
cp = hash;
})
user.password = cp;
user.resetToken ='';
user.save();
});
return res.redirect('/login');
})
my user.password is empty and i get this : Cannot set property 'password' of null -> becouse i set that in UserSchema.
So why is that ? i tried with console.logs in other function just with variables and is something like that :
bcrypt.hash(.... {console.log('a') })
console.log('b');
my console looks like this :
b
a
So bcrypt console.log is after. What can i do ?
Please note that User.findOne() is an async operation.
The redirection res.redirect('/login') should be called after new password is saved.
You could try this code below:
router.post('/reset/:id', function (req, res, next) {
if (req.body.newPassword === req.body.confirmNewPassword) {
User.findOne({
'resetToken': req.params.id.trim()
}, function (error, user) {
if (error) return next(error);
bcrypt.hash(req.body.password, 5, function (err, hash) {
if (err) {
return next(err);
}
user.password = hash;
user.resetToken = '';
user.save();
// Do the redirection here
res.redirect('/login');
})
});
}
// Do nothing here
})

Node.js module error handling

I've been struggling last week with error handling, especially error handling in Node.js modules. So first, here is my code:
user.js route
router.post('/register', function(req, res) {
var newUser = new User({
firstname: req.body.firstname,
lastname: req.body.lastname,
email: req.body.email,
password: req.body.password,
});
User.addUser(newUser, function(err, user) {
if(err) {
return next(err)
} else if(user) {
res.status(403).send('User already exists');
} else {
res.sendStatus(200);
}
});
});
user.js module
module.exports.addUser = function(newUser, cb) {
User.findOne({ email: newUser.email }, function(err, user) {
if(err) {
cb(err);
} else if(user) {
cb(null, user);
} else {
bcrypt.genSalt(10, function(err, salt) {
if(err) {
cb(err);
} else {
bcrypt.hash(newUser.password, salt, function(err, hash) {
if(err) {
cb(err)
} else {
newUser.password = hash;
newUser.save(function(err, newUser) {
if(err) {
cb(err);
} else {
cb(null, false);
}
});
}
});
}
});
}
});
}
Everytime if there is error inside user.js module, call callback function and handle error inside user.js route. This works, but that mess inside my module doesn't look good, because there is so many if-else statements..
Is there better approach, or do I have to check everytime if there is error?
You could simplify your code to something like:
module.exports.addUser = function(newUser, cb) {
User.findOne({ email: newUser.email }, function(err, user) {
if(err) {
cb(err);
return;
}
if(user) {
cb(null, user);
return ;
}
bcrypt.genSalt(10, function(err, salt) {
if(err) {
cb(err);
return;
}
bcrypt.hash(newUser.password, salt, function(err, hash) {
if(err) {
cb(err)
return;
}
newUser.password = hash;
newUser.save(function(err, newUser) {
if(err) {
cb(err);
return;
}
cb(null, false);
});
});
});
});
}
However, if I were you and as #Scimonster stated in his comment, this is a typical use case for promises that would allow you to write more readable code and avoid the callback hell

Error in sign up passport-local sign up routine

I'm building an app in Node, using Passport and local signup and sign in strategies. I just keep running into an issue. All the required modules etc. are there. The following sign in routine works fine:
passport.use('local-signin', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('message', 'User not found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('message', 'Wrong password.'));
return done(null, user);
});
}));
However, the following sign up routine does not:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
console.log("signing up")
User.findOne({ 'local.email' : email }, function(err, user) {
if (err) {
return done(err);
} else if (user) {
return done(null, false, req.flash('message', 'That email address is already registered.'));
} else {
var newUser = new User();
}
// save the user
newUser.save(function(err) {
if (err) {
console.log("Error saving new user profile: " + err);
} else {
return done(null, newUser, req.flash('message', 'User account created'));
}
});
});
}))
Both routines are called within routes.js:
// POST : SIGNUP
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect: '/error',
failureFlash: true
}));
// POST : SIGNIN
app.post('/signin', passport.authenticate('local-signin', {
successRedirect: '/profile',
failureRedirect: '/',
failureFlash: true
}));
Any ideas where it might go wrong? As is, posting to /signup continuously results in a failureRedirect. My head is getting kinda sore from banging on the screen...
The only thing you need to change is:
if (!user.validPassword(password))
To
if (user.validPassword(password) === false)
I know, if (!user.validPassword(password)) is in examples on Passport.js official docs, but it is wrong.
I have just lost 2 hours of my life, figuring this out.
Use this code it will helps you to fix your problem
passport-authentication.js
var express=require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/user');//user is schema
var Verify = require('./verify');//verify is a file where the user is verified
/* GET users listing. */
router.get('/', Verify.verifyOrdinaryUser,function(req, res, next) {
User.find({},function(err,user){
if(err) throw err;
res.json(user);
});
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username,Email:req.body.Email}),
req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
if(req.body.firstname) {
user.firstname = req.body.firstname;
}
if(req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
verify.js
var User = require('../models/user');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
hope this helps for you...

Categories

Resources