express status code not updating, getting json message update - node.js

I am not getting status message as 500 eventhough I set. always getting status message as 200. how to set the status as 500?
here is my code : "express": "4.17.2",
router.post('/register', async (req: Request, res: Response) => {
const { password, email } = req.body;
try {
const isUserExist = await UserModel.findOne({ email: email });
if (isUserExist) {
//status not set.
return res.json({ message: 'User already exist', success: false }).status(500);
}
const hashPassword = bcrypt.hashSync(password, 10);
req.body.password = hashPassword;
const newUser = new UserModel(req.body);
await newUser.save();
res.json({ message: 'user created successfully', success: true });
} catch (error) {
res.sendStatus(500).json({ message: 'Error creating user', success: false });
}
});
react axios:
when i use:
return res.status(500).json({ message: 'User already exist', success: false }); getting something went wrong
export const registerUser = createAsyncThunk('post/user', async (user: RegisterFormProps) => {
try {
const response = await axios.post(environment.BASE_URL + '/user/register', user);
console.log('suc', response.data.success);
if (response.data.success) {
toast.success(response.data.message);
} else {
toast.error(response.data.message);
}
} catch (error) {
const err = error as AxiosError;
console.log('err', err);
toast.error('something went wrong');
}
});

You should be using res.status instead of res.sendStatus in your code.
res.status(statusCode) just sets the status on the response.
whereas res.sendStatus(statusCode) sends the response after setting the status.
for example:
res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
on the client side try using error.response.data in your catch block

Try this one:
router.post('/register', async (req: Request, res: Response) => {
const { password, email } = req.body;
try {
const isUserExist = await UserModel.findOne({ email: email });
if (isUserExist) {
//status not set.
return res.status(500).json({ message: 'User already exist', success: false });
}
const hashPassword = bcrypt.hashSync(password, 10);
req.body.password = hashPassword;
const newUser = new UserModel(req.body);
await newUser.save();
res.status(201).json({ message: 'user created successfully', success: true });
} catch (error) {
res.status(500).json({ message: 'Error creating user', success: false });
}
});

Related

Troubles with passport js and react getting user with fetch

Hello guys I have a problem trying to get my user session with passport on reactjs. I have no problem to get on post man , I cannot fetch the data with a Get method on react js, im getting undefined:(.
I configurated my cors and everything and still no data :(.
This is my fetch
const [user, setUser] = useState(null);
useEffect(() => {
const getUser = async () => {
try {
const response = await axios.get("http://localhost:8080/login/success");
const data = await response.json();
setUser(data);
} catch (error) {
throw new Error(`error fetching data ${error}`);
}
};
getUser();
}, []);
and this is my end point and passport js config.
function checkAuthentication(req, res, next) {
if (req.isAuthenticated()) next();
else {
res.status(401).json({
message: "Failure",
});
}
}
router.get("/login/success", checkAuthentication, (req, res) => {
if (req.user) {
res.status(200).json({
success: true,
message: "success user",
user: req.user,
});
console.log(req.user);
} else {
req.status(404).json({
success: false,
message: "No user",
})
}
});
passport.use(
"login",
new LocalStrategy(async (username, password, done) => {
try {
const user = await User.findOne({ username: username });
if (!user) {
return done(null, false, { message: "Incorrect username" });
}
const isMatch = await user.isValidPassword(password);
if (!isMatch) {
return done(null, false, { message: "Incorrect password" });
} else {
return done(null, user, { message: "Logged in successfully" });
}
} catch (error) {
console.log(error);
}
})
);

keeps getting "Illegal arguments: undefined, string at Object.bcrypt.hashSync"

I've been struggling with Bcrypt on my MERN project I'm trying to create an authentication system I'm trying to run tests on Postman and I'm not sure why do I keep getting the error: "Illegal arguments: undefined, string at Object.bcrypt.hashSync"
this is my postman request:
this is the Controller Code:
const config = require("../config/auth.config");
const db = require("../models");
const User = db.user;
const Role = db.role;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
exports.signup = (req, res) => {
const user = new User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
user.save((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (req.body.roles) {
Role.find(
{
name: { $in: req.body.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = roles.map((role) => role._id);
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
}
);
} else {
Role.findOne({ name: "user" }, (err, role) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = [role._id];
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
});
}
});
};
exports.signin = (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password!" });
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
email: user.email,
roles: authorities,
});
});
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({ message: "You've been signed out!" });
} catch (err) {
this.next(err);
}
};
The error message:
Illegal arguments: undefined, string at Object.bcrypt.hashSync wants to say that you're passing undefined as an argument to the hashSync function. We need to fix this error.
Take a closer look at this line where the error occurs:
password: bcrypt.hashSync(req.body.password, 8),
req.body.password is undefined, you can verify it by console.log(req.body.password). What's wrong is that you are sending data as URL parameters. So req.body is an empty object and req.body.password is undefined.
In Postman, select the Body tab, choose JSON format, then type your data as a JSON object. Then, in your code, use express.json() middleware to parse requests in JSON format. You'll have the desired output.
You can see my example request in Postman below:

Why do I get this error : Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am trying to create a simple registration using passsport-local and passport-jwt modules using the following code as my reister root/controller:
var passport = require('passport');
const User = require('../model/User');
const handleNewUser = async (req, res) => {
const { email, password } = req.body;
if (!email || !password) return res.status(400).json({ 'message': 'Username and password are required.' });
// check for duplicate usernames in the db
const duplicate = await User.findOne({ email: email }).exec();
if (duplicate) return res.sendStatus(409); //Conflict
try {
const result = User.register(new User({username : req.body.email}), req.body.password, (err , user) => {
if (err) {
res.statusCode(500);
res.setHeader('Content-Type', 'application/json');
res.json({ err: err });
} else {
console.log('success');
passport.authenticate('local')(req, res, () => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json({ success: true, status: 'Registration Successful' });
});
}
});
console.log(result);
res.status(201).json({ 'success': `New user ${user} created!` });
} catch (err) {
res.status(500).json({ 'message': err.message });
}
}
module.exports = { handleNewUser };
And this is the error I do get:
POST /register
undefined
node:internal/errors:465
ErrorCaptureStackTrace(err);
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
And it happens here:
res.setHeader('Content-Type', 'application/json');
I don't know why do I get this error message and how can I fix it?

How to switch back to async/await?

I am new to async/await so I have an exercise like below code, I have converted this code to async/await many times and still no success. Please help me. Thanks very much!
My code is as follows:
exports.register = (req, res) => {
const user = req.body;
try {
// Validate the registration form
validateRegisterForm(user)
.then((response) => {
// If response is true, hash the password
if (response) {
Md5Password(user.password)
.then(async (hash) => {
const { name, email } = user;
const newUser = new User({
name,
password: hash,
});
// Save the user
const savedUser = await newUser.save();
res.status(200).json(savedUser);
})
.catch((error) => {
res.status(500).json({
message: error.message,
err: "500: Internal Server Error",
});
});
}
// But if response is false, show the error message
else {
res.status(401).json({
message: errorMessage(),
error: "401: Unauthorized",
});
}
})
.catch((error) => {
res.status(500).json({
message: error.message,
err: "500: Internal Server Error",
});
});
} catch (error) {
res.status(500).json({
error: error.message,
message: "registration failed",
e: "500: Internal Server Error",
});
}
};
Please help me, thanks a lot!
Not sure exactly what you're trying to achieve, but here's a version of your code with async/await:
exports.register = async (req, res) => {
const user = req.body;
try {
// Validate the registration form
const response = await validateRegisterForm(user);
// If response is true, hash the password
if (response) {
const hash = await Md5Password(user.password);
const { name, email } = user;
const newUser = new User({
name,
password: hash,
});
// Save the user
const savedUser = await newUser.save();
res.status(200).json(savedUser);
} else {
res.status(401).json({
message: errorMessage(),
error: "401: Unauthorized"
});
}
} catch (e) {
res.status(500).json({
message: e.message,
err: "500: Internal Server Error"
});
}
}

Keep getting "Can't set headers after they are sent" using Node/Express

I keep getting "Can't set headers after they are sent" building a Node/Express API.
The issue is I am not setting the headers after the response has been sent anywhere. I am always calling res.status(xxx).json({}) to close ever condition.
Route
const router = require('express').Router();
router.get('/password/validate/:hash', PasswordController.validate);
router.post('/password/update', PasswordController.update);
Controller
This is where the error is occurring. I am calling the validate request specifically.
// Import node packages
const mongoose = require('mongoose');
const Password = require('../models/password');
const User = require('../models/user');
const bcrypt = require('bcryptjs');
const moment = require('moment');
const string = require('../middleware/string_functions')
exports.update = (req, res, next) => {
User.findOne({ email: req.body.email })
.exec()
.then(user => {
if (!user) {
res.status(401).json({
message: 'Cannot retrieve account'
})
}
const expiry = moment().add(30, 'seconds');
const unique_string = string.generate_random(32);
const url_hash = string.base64_encode(unique_string +':'+ user._id);
bcrypt.hash(unique_string, 10, (err, hash) => {
if (err) {
res.status(500).json({
error: err.message
})
}
const query = { user_id: user._id }
const newData = {
hash,
expiry
}
Password.findOneAndUpdate(query, newData, { upsert: true, new: true })
.exec()
.then(request => {
res.status(201).json({
message: 'success',
url: 'localhost:8081/users/password/validate/' + url_hash,
data: request
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
exports.validate = (req, res, next) => {
if (!req.params.hash) {
res.status(500).json({
error: 'Missing hash'
})
}
const data = string.base64_decode(req.params.hash).split(':');
console.log(data)
Password.findOne({ user_id: data[1] })
.exec()
.then(request => {
if (!request) {
res.status(404).json({
message: 'Change request not found or expired'
})
}
bcrypt.compare( data[0], request.hash, (err, result) => {
if (err) {
res.status(500).json({
error: err.message
})
}
if (result) {
if (moment().isAfter(request.expiry)) {
res.status(401).json({
message: 'Time has expired'
})
}
res.status(200).json({
message: 'Hash validation successful'
})
}
res.status(500).json({
error: 'Something went wrong'
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
Console Error
_http_outgoing.js:494
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
at ServerResponse.setHeader (_http_outgoing.js:501:3)
at ServerResponse.header (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/express/lib/response.js:267:15)
at bcrypt.compare (/Users/chrislloyd/Development/Projects/happy-hour-api/api/controllers/passwords.js:83:22)
at /Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/bcryptjs/dist/bcrypt.js:297:21
at /Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/bcryptjs/dist/bcrypt.js:1353:21
at Immediate.next [as _onImmediate] (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/bcryptjs/dist/bcrypt.js:1233:21)
at runCallback (timers.js:789:20)
at tryOnImmediate (timers.js:751:5)
at processImmediate [as _immediateCallback] (timers.js:722:5)
Updated Example
exports.update = (req, res, next) => {
// Check if hash value exists
if (!req.params.hash) {
res.status(500).json({
error: 'Missing hash value'
});
return;
}
// Check if password and confirmation are the same
if (req.body.password != req.body.passwordConfirmation) {
res.status(401).json({
message: 'Password confirmation does not match'
});
return;
}
// Decode and split hash and user id into array
const data = string.base64_decode(req.params.hash).split(':');
// Find record that contains user id
Password.findOne({ user_id: data[1] })
.exec()
.then(request => {
console.log(request)
// Throw 404 error if record is not found
if (!request) {
return res.status(404).json({
message: 'Password change request doest not exist or timed out'
});
}
// Check if change request has expired
if (moment().isAfter(request.expiry)) {
res.status(401).json({
message: 'Password change request expired',
request: {
request: 'http://localhost:3001/users/password/request'
}
});
// Delete expired record
Password.remove({ _id: request._id })
.exec()
.catch(err => {
res.status(500).json({
error: err.message
});
});
return;
}
// Compare hash value from encoded string to encrypted hash value in database
console.log(mongoose.Types.ObjectId(request.user_id))
bcrypt.compare( data[0], request.hash, (err, result) => {
// Bcrypt error performing comparison
if (err) {
res.status(500).json({
error: err.message
});
return;
}
// Check if result is true
if (result) {
// Find user record matching request.user_id and update password
User.findOneAndUpdate({ _id: mongoose.Types.ObjectId(request.user_id) }, {$set: { password: req.body.password }}, {new: true}, (err, user) => {
console.log(user)
// Error finding and updating user record
if (err) {
res.status(500).json({
error: err.message
});
return;
}
// If returned user account is not null
if (user) {
res.status(200).json({
message: 'Password updated',
user
});
return;
}
// Could not find user record
res.status(404).json({
message: 'Could not find user account to update'
});
return;
})
}
// Catch all error
res.status(500).json({
error: 'Something went wrong'
});
return;
})
})
.catch(err => {
res.status(500).json({
error: err.message
});
return;
});
}
That particular error is caused when you send multiple responses to the same request.
You see to be thinking that as soon as you do res.status(...).json(...) that your function returns and stops executing. It does not. res.json() is just a regular function call. It doesn't change the control flow in your function at all (unless it throws an exception). A successful call to res.json() executes and then your function just keeps right on executing the lines of code that follow.
What you need is a return statement after each time you send a response (if there is any other code in your function that could execute and send another response) so that your function doesn't continue to execute and send another response or you could bracket your responses in if/else statements so you don't execute the sending of more than one response.
Here's a fixed version with 5 added return statements to keep the rest of your code from executing after you've sent a response and to keep you from sending multiple responses to the same request. Each addition is commented with ==> added:
// Import node packages
const mongoose = require('mongoose');
const Password = require('../models/password');
const User = require('../models/user');
const bcrypt = require('bcryptjs');
const moment = require('moment');
const string = require('../middleware/string_functions')
exports.update = (req, res, next) => {
User.findOne({ email: req.body.email })
.exec()
.then(user => {
if (!user) {
res.status(401).json({
message: 'Cannot retrieve account'
})
return; // <== added
}
const expiry = moment().add(30, 'seconds');
const unique_string = string.generate_random(32);
const url_hash = string.base64_encode(unique_string +':'+ user._id);
bcrypt.hash(unique_string, 10, (err, hash) => {
if (err) {
res.status(500).json({
error: err.message
})
return; // <== added
}
const query = { user_id: user._id }
const newData = {
hash,
expiry
}
Password.findOneAndUpdate(query, newData, { upsert: true, new: true })
.exec()
.then(request => {
res.status(201).json({
message: 'success',
url: 'localhost:8081/users/password/validate/' + url_hash,
data: request
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
exports.validate = (req, res, next) => {
if (!req.params.hash) {
res.status(500).json({
error: 'Missing hash'
})
}
const data = string.base64_decode(req.params.hash).split(':');
console.log(data)
Password.findOne({ user_id: data[1] })
.exec()
.then(request => {
if (!request) {
res.status(404).json({
message: 'Change request not found or expired'
})
return; // <== added
}
bcrypt.compare( data[0], request.hash, (err, result) => {
if (err) {
res.status(500).json({
error: err.message
})
return; // <== added
}
if (result) {
if (moment().isAfter(request.expiry)) {
res.status(401).json({
message: 'Time has expired'
})
}
res.status(200).json({
message: 'Hash validation successful'
})
return; // <== added
}
res.status(500).json({
error: 'Something went wrong'
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
The res object by itself does not stop the execution of your program. You must use return if you prefer to use Guard Clauses instead of Nested Conditions
Replace statements like this:
if (err) {
res.status(500).json({
error: err.message
})
}
With this:
if (err) {
res.status(500).json({
error: err.message
});
return; // return statement added
}

Resources