Express "Can't set headers after they are sent" after deploying to Heroku - express

after deploying my server code to Heroku I'm getting the error "Can't set headers after they are sent". I fetch my login data
fetch("url", {
method: "POST",
mode: "cors",
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
//"Content-Type": "application/json"
},
body: requestBody
}).then((res, next) => {
if(res.ok){
res.json().then((json) => {
if(json.verifystate){
this.props.navigation.navigate('Home')
}
else{
this.setState({isAuthentic:false});
}
});
}else{
next();
}
})
And it calls my server post method
app.post('/users/auth', function(req, res) {
loginData(db, req.body.email, req.body.password, req.body.mphone, function(result){
if(result == 1){
res.send({"verifystate":1});
}else if(result == 2){
res.send({"verifystate":2});
}else{
res.send({"verifystate":3});
}
});
//console.log('json: '+JSON.stringify(data));
});
edit: Login function
module.exports = function loginData(db, email, myPlaintextPassword, mphone, callback){
var collectionUser = db.collection('users');
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
var queryStr = {"emails.address": email};
collectionUser.findOne(queryStr, function(err, result) {
if(err)
{
return;
}else if(result != null){
bcrypt.compare(myPlaintextPassword, result.services.password.bcrypt, function(err, res) {
console.log("conpare result: ", res);
if(res){
callback("1");
}else{
callback("3");
}
});
if(!result.services.resume || result.services.resume.appLoginToken == null
|| !result.services.resume.appLoginToken.date || !result.services.resume.appLoginToken.base64Token){
var tokenStr = email + Math.random(1,100);
tokenStr = Base64.encode(tokenStr);
queryStr = {
"services.resume.appLoginToken.date": Date(),
"services.resume.appLoginToken.base64Token": tokenStr
};
var newDate = { "services.resume.appLoginToken.date": Date() }
var temp = {"emails.address": email};
collectionUser.update(temp,
{ $set: {"services.resume.appLoginToken.date": Date()} }, function(err, result) {
if(err)
{
return;
}else {
}
});
collectionUser.update(temp,
{ $set: {"services.resume.appLoginToken.base64Token": tokenStr} }, function(err, result) {
if(err)
{
return;
}else {
}
});
}else{
console.log("already have token");
}
}else{
callback("2")
}
});
});
});
};
And when it gets to res.send({"verifystate:"1}) it then throws the aforementioned error. Any help would be great thanks.

if(!res.headersSent){
res.send('hello world');
}
or
if(!res.headersSent){
res.json({message: 'hello world'});
}
you probably have a callback that fires more than once, often times this is with event emitters.
As a side note, I really recommend using 2 spaces for indentation with JS, because so much code is nested. And I also recommend putting else and .then() on a newline, more readable.

I did not read the whole code but you could try this:
module.exports = function loginData(db, email, myPlaintextPassword, mphone, callback) {
let collectionUser = db.collection('users');
bcrypt.genSalt(saltRounds, function (err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function (err, hash) {
let queryStr = {"emails.address": email};
collectionUser.findOne(queryStr, function (err, result) {
if (err) {
//You should do something here or it would take you to an error , just an return won't work, you've to call a callback that send the error message
//callback(0)
} else if (result !== null) {
if (!result.services.resume || result.services.resume.appLoginToken === null
|| !result.services.resume.appLoginToken.date || !result.services.resume.appLoginToken.base64Token) {
let tokenStr = email + Math.random(1, 100), temp = {"emails.address": email};
tokenStr = Base64.encode(tokenStr);
queryStr = {
"services.resume.appLoginToken.date": new Date(),
"services.resume.appLoginToken.base64Token": tokenStr
};
collectionUser.update(temp,
{$set: {"services.resume.appLoginToken.date": new Date()}}, function (err, result) {
});
collectionUser.update(temp,
{$set: {"services.resume.appLoginToken.base64Token": tokenStr}}, function (err, result) {
});
} else {
console.log("already have token");
}
bcrypt.compare(myPlaintextPassword, result.services.password.bcrypt, function (err, res) {
console.log("conpare result: ", res);
if (res) {
callback(1);
} else {
callback(3);
}
});
} else {
callback(2);
}
});
});
})
};
And this:
app.post('/users/auth', function (req, res) {
loginData(db, req.body.email, req.body.password, req.body.mphone, function (result) {
res.send({verifystate: result});
});
});

Related

no response after axios.post()

Hey I'm working on a Login system on my vue project and have the problem that there seems to be no response from the backend.
This is the backend function:
auth.post('/login', async function (req, res) {
const { email, password } = req.body;
console.log(req);
if(email !== "" && password !== "") {
const account = await User.findOne({ where: { email: email} });
if (account) {
if (await account.validPassword(password)) {
// Generate an access token
const accessToken = jwt.sign({ id: account.id }, SECRET);
const account_data =
{
'id': account.id,
'firstName': account.firstName,
'lastName': account.lastName,
'email': account.email,
'isAdmin': account.isAdmin
}
res.send({accessToken, account_data});
} else {
res.status(200).json("Username or password incorrect");
}
} else {
res.send('Username or password incorrect');
}
} else {
res.send('Username or password incorrect');
}
})
This is the method were I call the action
methods: {
async loginUser(){
let user = await this.$store.dispatch('loginUser', this.loginInfo);
if(user.error){
alert(user.error)
} else {
alert('Thank you for signing in, ' + user.firstName);
}
},
}
This is the action:
async loginUser({commit}, loginInfo){
console.log(loginInfo)
try{
let response = await axios({
method: 'POST',
url: 'http://localhost:4000/api/auth/login',
data: loginInfo,
headers: {
// Overwrite Axios's automatically set Content-Type
'Content-Type': 'application/json'
}});
let user = response.data;
console.log(user);
commit('SET_CURRENT_USER', user);
} catch (e){
alert(e);
return {e}
}
}
Neither the console.log in the try function or in the catch function is triggered.

Return Values from a callback SQL function in node.js

Currently I'm working on a node.js application, with a register function. For this function I need to check a username is already taken or not. Unfortunately the SQL module in node just accepts a callback function from which I cannot send any booleans back.
Here is some code from my controller module:
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
const userExists = model.checkIfUserExists(newUser.userName);
if (userExists == false){
// create new user
} else {
// Send json back "user already exists
}
res.status(201).json(newUser);
} catch {
res.status(500);
}
}
And here is the code of the model:
function checkIfUserExists(Username){
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err){
throw err;
}
console.log(result);
if (result.length > 0){
return true;
} else {
return false;
}
});
}
Unfortunately the "checkIfUserExists" method never returns back a true or false which leads to the "userExists " variable to be null.
I'd like to know how to do return the bollean there or how to solve the problem in a more elegant way.
Please help me to fix this code. Thanks :)
You can either pass a callback to checkIfUserExists or use promises. If I were you, and since you are already using async/await, I would make your return of checkIfUserExists be a promise. So...your code could become
function checkIfUserExists(Username) {
return new Promise((resolve,reject) => {
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err) {
throw err;
}
console.log(result);
if (result.length > 0) {
resolve()
} else {
reject()
}
});
})
}
Then, your code that calls this function would be:
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
await model.checkIfUserExists(newUser.userName).catch(() => {
// Send json back "user already exists
});
// create user
res.status(201).json(newUser);
} catch {
res.status(500);
}
}
First check your catch statement and also add await before model.checkIfUserExists(newUser.userName)
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
const userExists = await model.checkIfUserExists(newUser.userName);
if (userExists == false){
// create new user
} else {
// Send json back "user already exists
}
res.status(201).json(newUser);
} catch(ex) {
res.status(500);
}
}
return promise from this function:
function checkIfUserExists(Username){
return new Promise((resolve, reject) => {
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err){
return reject(err);
}
console.log(result);
if (result.length > 0){
return resolve(true);
} else {
return resolve(false);
}
});
})
}

user.comparePassword is not a function

I got stuck on hashed password validation with bcrypt-nodejs, nodeJS (expressJS) and mongoose. User can register and code generates hashed password but when I try to validate that password with comparePassword function in login page it does not work and gives me error user.comparePassword is not a function
Here is the code:
Database:
UserSchema.pre('save', async 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,null, function(err,hash){
if(err) return next(err)
user.password = hash
next()
})
})
})
UserSchema.methods.comparePassword = async function(candidatePassword, cb){
bcrypt.compare(candidatePassword, this.password, function(err, isMatch){
if(err) return cb(err);
cb(null, isMatch)
})
}
Route:
router.post('/', async (req, res) => {
try {
const {username, password} = req.body;
const user = await User.findOne({username}).lean();
if (!user) {
return res.status(404).send({
message: 'user is not registered'
});
}
if(username.trim().length < 1 && password.trim().length < 1){
return res.status(409).send({message: 'username & password is required'})
}
// if (user.password !== password) {
// return res.status(403).send({
// message: 'user password invalid'
//});
//}
user.comparePassword(password, function(err, isMatch){
if(err){
return res.status(500).send({message: err.message})
}
if(!isMatch){
return res.status(403).send({
message: 'user password invali'
});
}
req.session.user = user;
const redirectTo = '/dashboard';
if (
req.is('application/json') // request content type is json
|| // or
req.xhr // is ajax
) {
// respond with json response
return res.status(200).send({redirectTo});
}
// not ajax request
// then respond redirect header
res.redirect(redirectTo);
})
const mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
SALT_WORK_FACTOR = 10;
const userDataModal = mongoose.Schema({
username: {
type: String,
required : true,
unique:true
},
password: {
type: String,
required : true
}
});
userDataModal.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();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
userDataModal.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
// Users.index({ emaiId: "emaiId", fname : "fname", lname: "lname" });
const userDatamodal = module.exports = mongoose.model("usertemplates" , userDataModal)
//inserting document
userDataModel.findOne({ username: reqData.username }).then(doc => {
console.log(doc)
if (doc == null) {
let userDataMode = new userDataModel(reqData);
// userDataMode.password = userDataMode.generateHash(reqData.password);
userDataMode.save({new:true}).then(data=>{
let obj={
success:true,
message: "New user registered successfully",
data:data
}
resolve(obj)
}).catch(err=>{
reject(err)
})
}
else {
resolve({
success: true,
docExists: true,
message: "already user registered",
data: doc
}
)
}
}).catch(err => {
console.log(err)
reject(err)
})
//retriving and checking
// test a matching password
user.comparePassword(requestData.password, function(err, isMatch) {
if (err){
reject({
'status': 'Error',
'data': err
});
throw err;
} else {
if(isMatch){
resolve({
'status': true,
'data': user,
'loginStatus' : "successfully Login"
});
console.log('Password123:', isMatch); // -> Password123: true
}

ExpressJS Multer: Upload image to server

I'm newer with Node.js and Express.js.
I want to upload first a image into the server (directory: uploads/spots), and then (synchronous) upload the rest of form data in MongoDB.
I'm using REST (Method Post)
app.route('/spots').post(users.requiresLogin, spots.create);
and I'm using Multer for updating the image into the server, and works.
app.use(multer(
{ dest: './public/uploads/spots',
onFileUploadStart: function (file) {
var imagePath = file.path;
gm(imagePath).resize(850, 850).quality(70).noProfile().write('public/uploads/spots/850x850/'+file.name, function (err) {
if (!err) {
gm(imagePath).resize(150, 150).quality(70).noProfile().write('public/uploads/spots/150x150/'+file.name, function (err) {
if (!err) {
}
else{
console.log('Error: '+err);
}
});
}
else{
console.log('Error: '+err);
}
});
}
}));
Is working, but is asynchronous , and returns the response to frontend before that the image will be upload into the server.
My question is how to do this but synchronous and how to return the response to the frontend after that the image was uploaded.
Thank you!
spots.server.routes.js
'use strict';
module.exports = function(app) {
var gm = require('gm');
var multer = require('multer');
var users = require('../controllers/users.server.controller.js');
var spots = require('../controllers/spots.server.controller.js');
//Upload image
app.use(multer(
{ dest: './public/uploads/spots',
onFileUploadStart: function (file) {
var imagePath = file.path;
gm(imagePath).resize(850, 850).quality(70).noProfile().write('public/uploads/spots/850x850/'+file.name, function (err) {
if (!err) {
gm(imagePath).resize(150, 150).quality(70).noProfile().write('public/uploads/spots/150x150/'+file.name, function (err) {
if (!err) {
}
else{
console.log('Error: '+err);
}
});
}
else{
console.log('Error: '+err);
}
});
}
}));
// Spots Routes
app.route('/spots')
.get(spots.list)
.post(users.requiresLogin, spots.create);
app.route('/spots/:spotId')
.get(spots.read)
.put(users.requiresLogin, spots.update)
.delete(users.requiresLogin, spots.hasAuthorization, spots.delete);
// Finish by binding the Spot middleware
app.param('spotId', spots.spotByID);
};
spots.server.controller.js (create method)
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
errorHandler = require('./errors.server.controller.js'),
Spot = mongoose.model('Spot'),
_ = require('lodash'),
fs = require('fs');
/**
* Create a Spot
*/
exports.create = function(req, res) {
var spot = new Spot(JSON.parse(req.body.spot));
spot.user = req.user;
if(req.files.file)
spot.image=req.files.file.name;
else
spot.image='default.jpg';
spot.save(function(err) {
if (err) {
fs.unlinkSync('public/uploads/spots/'+spot.image);
fs.unlinkSync('public/uploads/spots/850x850/'+spot.image);
fs.unlinkSync('public/uploads/spots/150x150/'+spot.image);
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
var socketio = req.app.get('socketio'); // tacke out socket instance from the app container
socketio.sockets.emit('spot.created.'+spot.municipality, {spot:spot, user:req.user});
socketio.sockets.emit('spot.created.'+spot.province, {spot:spot, user:req.user});
socketio.sockets.emit('spot.created.'+spot.community, {spot:spot, user:req.user});
socketio.sockets.emit('spot.created.'+spot.country, {spot:spot, user:req.user});
res.jsonp(spot);
}
});
};
/**
* Spot authorization middleware
*/
exports.hasAuthorization = function(req, res, next) {
if (req.spot.user.id !== req.user.id) {
return res.status(403).send('User is not authorized');
}
next();
};
The solution is not use onFileUploadStart method and use a function with callback in the controller.
routes
// Spots Routes
app.route('/spots')
.get(spots.list)
.post(users.requiresLogin,multer({ dest: './public/uploads/spots'}), spots.create);
controller
exports.create = function(req, res) {
if (req.files.file)
exports.uploadImage(req.files.file,callback);
else
callback();
function callback(){
var spot = new Spot(JSON.parse(req.body.spot));
spot.user = req.user;
if (req.files.file)
spot.image = req.files.file.name;
else
spot.image = 'default.jpg';
spot.save(function (err) {
if (err) {
fs.unlink('public/uploads/spots/850x850/'+spot.image);
fs.unlink('public/uploads/spots/150x150/'+spot.image);
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
var socketio = req.app.get('socketio'); // tacke out socket instance from the app container
socketio.sockets.emit('spot.created.' + spot.municipality, {spot: spot, user: req.user});
socketio.sockets.emit('spot.created.' + spot.province, {spot: spot, user: req.user});
socketio.sockets.emit('spot.created.' + spot.community, {spot: spot, user: req.user});
socketio.sockets.emit('spot.created.' + spot.country, {spot: spot, user: req.user});
req.spot = spot;
Feedback.subscribeSpot(req);
Notify.getLocalSubscriptors(spot.municipality,spot.province,spot.community,spot.country,function(subscriptions){
Notify.create(req,null,spot,null,null,null,subscriptions,'spots/'+spot._id,false,'SPOT_CREATED', function(){
res.jsonp(spot);
});
});
}
});
}
};
exports.uploadImage = function(file, fn){
var imagePath = file.path;
gm(imagePath).resize(850, 850).quality(70).noProfile().write('public/uploads/spots/850x850/'+file.name, function (err) {
if (!err) {
gm(imagePath).resize(150, 150).quality(70).noProfile().write('public/uploads/spots/150x150/'+file.name, function (err) {
if (!err) {
if(fn)fn();
}
else{
console.log('Error: '+err);
}
});
}
else{
console.log('Error: '+err);
}
});
};

Keep having issues serializing and deserializing my PassportJS users

I'm using sequelize.js for my data store and the github strategy with passport.js. My code is:
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GitHubStrategy({
clientID: '123',
clientSecret: '456',
callbackURL: "" + config.hostname + ":" + config.port + "/auth/github/callback"
}, function(accessToken, refreshToken, profile, done) {
var authProviderQuery, newUser;
console.log('accessToken');
console.log(accessToken);
authProviderQuery = {
authId: profile.id
};
newUser = {
name: profile.username,
email: profile.emails[0].value
};
return DB.AuthProvider.find(authProviderQuery).complete(function(err, dbAuthProvider) {
var prop, _results;
if (err) {
return done(err);
}
if (!dbAuthProvider) {
return DB.User.create(newUser).complete(function(err, dbUser) {
var newAuthProvider;
if (err) {
return done(err);
}
newAuthProvider = {
name: 'github',
oathToken: accessToken,
authId: profile.id,
rawJSON: profile._raw
};
return dbUser.createAuthProvider(newAuthProvider).complete(function(err) {
if (err) {
return done(err);
}
return done(null, dbUser);
});
});
} else {
console.log(dbAuthProvider);
_results = [];
for (prop in dbAuthProvider) {
_results.push(console.log(prop));
}
return _results;
}
});
}));
passport.serializeUser = function(user, done) {
return done(null, user.id);
};
passport.deserializeUser = function(obj, done) {
return DB.User.find({
where: {
id: obj.id
}
}).complete(function(err, dbUser) {
console.log(dbUser);
return done(err, dbUser);
});
};
app.get('/auth/github', passport.authenticate('github'));
app.get("/auth/github/callback", passport.authenticate('github', {
failureRedirect: "/login"
}), function(req, res) {
return console.log('authenticated');
});
When I go to /auth/github, I get the following error:
/Users/mysite/node_modules/mysql/lib/protocol/Parser.js:82
throw err;
^
TypeError: object is not a function
What am I doing wrong?
You are replacing the serializeUser and deserializeUser methods from Passport instead of calling them to assign a (de)serializer - ie. you have
passport.deserializeUser = function(obj, done) {
...
};
when you should have
passport.deserializeUser(function(obj, done) {
...
});
See the documentation: http://passportjs.org/guide/configure/