Bcrypt password compare not showing results - node.js

I have come accross a strange problem. I have an if statement inside the bcrypt.compare(), which doesnt run at all.
Example
bcrypt.compare(req.body.password, data.password, function (err, result) {
if (!result || err) {
res.status(422).json({
message: "Wrong Password",
status: false,
statusCode: 422
})
}
});
const otherData = await findOne({
x : req.body.x
})
if(otherdata.x == "dummy") {
return res.status(200).json({
message: "wohhooo"
})
}
When i send wrong password in request body it should respond with message: "wrong password"
But it skips that if statement inside bcrypt.compare() and responds with message: "wohhoo"
In console I see, Error: Can't set headers after they are sent. with error pointing to return statement inside bcrypt.compare

[bcrypt.compare]1 is asynchronous function, So your program is executing res.status(200).json({message: "wohhooo"}) before bcrypt.compare
// Quick Fix
bcrypt.compare(req.body.password, data.password, function (err, result) {
if (!result || err) {
return res.status(422).json({
message: "Wrong Password",
status: false,
statusCode: 422
})
} else {
const otherData = await findOne({
x: req.body.x
})
if (otherdata.x == "dummy") {
return res.status(200).json({
message: "wohhooo"
})
}
}
});
Reference :
What the heck is a Callback?

Related

express status code not updating, getting json message update

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 });
}
});

Mongoose findOne always return undefined

When ever i tried to post this API via postman using email and password.
I get User Not Found. I cross checked email and password 100+ times.
In command prompt i am getting UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
What i am doing wrong here. Please tell me, Thank you in advance.
exports.loginUser = async (req, res) => {
try{
const user = await userTable.findOne({ email:req.body.email });
if (!user){
res.send({
status: 404,
message: "User Not Found"
});
}
const hashpass = cryptr.decrypt(user.password);
if (hashpass == req.body.password){
const accessToken = jwt.sign({ id: user._id, email: user.email }, process.env.JWT_PASS, {expiresIn:"1d"});
res.send({
status: 200,
data: user,
jwt: accessToken
});
}else{
res.send({
status: 404,
message: "Wrong password"
});
}
}catch(err){
res.status(500).send({
status: 0,
message: "catch issue" + err.message
});
};
};
I'm pretty sure this is happening because your handler continues after sending a response, therefore attempting to modify a response after it's already been sent.
Keep in mind, it could be how you are using the loginUser function. If you wouldn't mind updating your question showing us how you are using it, that would be super helpful!
There are a couple things that come to mind; 1. You may need to add a return statement somewhere, like on line 10/11 for example 2. You could also wrap the code after the first if statement inside an else statement to see if that changes things.
At the end of the day, I'm pretty sure your code is continuing after sending a response, which is why you see that error.
With return
exports.loginUser = async (req, res) => {
try {
let dataToSend = {};
const user = await userTable.findOne({ email: req.body.email });
if (!user) {
res.send({
status: 404,
message: "User Not Found",
});
// Try adding this
return;
}
const hashpass = cryptr.decrypt(user.password);
if (hashpass == req.body.password) {
const accessToken = jwt.sign({ id: user._id, email: user.email }, process.env.JWT_PASS, { expiresIn: "1d" });
res.send({
status: 200,
data: user,
jwt: accessToken,
});
} else {
res.send({
status: 404,
message: "Wrong password",
});
}
} catch (err) {
res.status(500).send({
status: 0,
message: "catch issue" + err.message,
});
}
};
Wrap in else
This is very ugly and should only be used to test in my opinion!
exports.loginUser = async (req, res) => {
try {
const user = await userTable.findOne({ email: req.body.email });
if (!user) {
res.send({
status: 404,
message: "User Not Found",
});
} else {
const hashpass = cryptr.decrypt(user.password);
if (hashpass == req.body.password) {
const accessToken = jwt.sign({ id: user._id, email: user.email }, process.env.JWT_PASS, { expiresIn: "1d" });
res.send({
status: 200,
data: user,
jwt: accessToken,
});
} else {
res.send({
status: 404,
message: "Wrong password",
});
}
}
} catch (err) {
res.status(500).send({
status: 0,
message: "catch issue" + err.message,
});
}
};

Express async route logging undefined after await

I am writing an Express endpoint in Typescript to update a user's password in the database, but having some trouble with multiple queries/synchronous code.
My problem is right now I am trying to await the return of a function but it doesn't seem to be awaiting.
My route looks like this:
router.put("/:userId", validateUser, async (req: any, res: Response) => {
const result: any = await updatePassword(req.body.password, req.body.confirmPassword, req.params.userId);
console.log(result) //LOGS UNDEFINED????
if (result.status !== 200) res.status(result.status).send({ message: result.message, code: result.code });
res.send("Success!");
});
and that updatePassword function looks like this:
const updatePassword = async (password: string, confirmPassword: string, userId: string) => {
if (password !== confirmPassword) {
return { status: 409, message: Errors.mismatchingPasswordMessage, code: Errors.mismatchingPasswordCode };
}
const hashedPassword = bcrypt.hashSync(password, 10);
//update the password in the DB
pool.query("UPDATE users SET password = ? WHERE userId = ?", [hashedPassword, userId], (err: MysqlError, result: any) => {
if (err) {
console.log(err);
return { status: 500, message: err.message, code: err.code };
}
if (result.changedRows !== 1) {
return { status: 500, message: "Password could not be updated!" };
}
return { status: 200 };
});
}
Why is this the route not correctly awaiting the result of updatePassword??
Thanks in advance for any help.
The problem is, you're mixing async/await and callback style in this part
pool.query("UPDATE users SET password = ? WHERE userId = ?", [hashedPassword, userId], (err: MysqlError, result: any) => {
if (err) {
console.log(err);
return { status: 500, message: err.message, code: err.code };
}
if (result.changedRows !== 1) {
return { status: 500, message: "Password could not be updated!" };
}
return { status: 200 };
});
The function updatePassword jumps directly to the next line after this block, which is nothing. So it returns undefined.
You need to replace this block with async/await code. Something like :
try {
const result = await pool.query("UPDATE users SET password = ? WHERE userId = ?", [hashedPassword, userId]);
if (result.changedRows !== 1) {
return { status: 500, message: "Password could not be updated!" };
}
return { status: 200 };
}
catch (err){
console.log(err);
return { status: 500, message: err.message, code: err.code };
}

Sending custom error from Node/Express to Angular

I am sending an HTTP request from angular to a node/express API. How do I get the actual error message I send from the node/express API
I am handling my exceptions well when they are thrown in the API but the moment I try to read the message in Angular I only get the name of the type of error I throw. For example, if I throw a 409 the error received by angular is just "Conflict" and does not contain the details I send. Please look at my code below.
I am sending my request as below
register(user: UserAccount) {
return this.http
.post(`${config.apiUrl}/users/register`, user)
.pipe(
map((res: HttpResponse<Response>) => {
return res;
}))
.pipe(catchError(err => this.errorHandler.handleError(err)));
}
My handle error is as below:
handleError(error: HttpErrorResponse) {
console.log(error);
if (error) {
let errMessage = '';
try {
errMessage = error.message;
} catch (error) {
errMessage = error.statusText;
}
return throwError(errMessage || error || 'Server error');
}
return throwError(error.error || error || 'Server error');
}
This how I am throwing my error when I occurs in my Node/Express API
registerUser (req, res) {
debug(chalk.blue(`*** insert user`))
userRepo
.create(req.body)
.then(user => {
debug(chalk.green(`*** Insert User ok!`))
res.status(200).json({
status: true,
error: null,
user: user
})
})
.catch(err => {
debug(chalk.red(`*** insertUser error: ${util.inspect(err)}`))
if (err['type'] && err['type'] === '409') {
res.status(409).json({
status: false,
error: err['message'],
user: null
})
} else {
res.status(400).json({
status: false,
error: err,
user: null
})
}
})
}
I want to be able to receive the json object with the information about the error but all I am getting when I access the error item is, for example, in the case of raising a 409, I only get 'Conflict'
The reason for this is that when you catch the error and the status is a 409, you return `err['message'] instead of 'err'.
So instead of:
res.status(409).json({
status: false,
error: err['message'],
user: null
})
You should return:
res.status(409).json({
status: false,
error: err,
user: null
})
This is actually what you do in the case of a 400 error!

Getting 400 Bad Request despite catching the err in angular2+

I have designed a login page where login is successful when i put a correct login and password and Login doesn't happen when I put an incorrect username or password which is correct. However, I get this error:
POST http://localhost:3003/login/authenticate 400 (Bad Request)
ERROR HttpErrorResponse {headers: HttpHeaders, status: 400, statusText: "Bad Request", url: "http://localhost:3003/login/authenticate", ok: false, …}
Everything works properly however, I get the error in the console. Like this:
I want the 400 bad request error to not appear in the console. How to do that?
login.component.ts
login(data) {
console.log("Inside Login");
this.authenticateObj = {
username: data.username,
password: data.password
}
this.http.post("http://localhost:3003/login/authenticate",
this.authenticateObj)
.map(Response => Response)
.catch((err) => {
console.log("err =", err)
alert('Login Failed. Username or Password
is incorrect');
return Observable.throw(err);
})
.subscribe((res: Response) => {
console.log("Inside login authenticate subscribe");
this.info = res;
if (this.info.message == 'Login Successful.') {
console.log("test after login = ", this.info);
if (localStorage.getItem('username') &&
localStorage.getItem('token')) {
alert('Login Successful');
this.router.navigate(['/file-upload/wsdl']);
} else {
this.notification.Error('Unauthorized');
}
}
if (this.info.message == 'error') {
alert('Login Failed');
}
else if (this.info.status == 400) {
alert('Login Failed');
}
})
}
login.controller.js
function authenticateUser(req, res, next) {
console.log("Inside authenticateUser = ", req.body)
LoginService.authenticate(req,req.body)
.then(function (token) {
if (token) {
res.setHeader("authorization",token.token);
res.send({
message: 'Login Successful.',
response: token
});
} else if(res.message == 'Username or Password is
incorrect'){
res.status(401).send({
message: 'Unauthorized. '
});
}
else {
console.log("inside controller, else res.status-400");
res.status(400).send({
message: 'Username or password is incorrect'
});
}
})
.catch(function (err) {
console.log("inside controller, catch res.status 400")
// res.status(400).send(err);
res.status(400).send({
message: 'Username or password is incorrect'
});
});
}
In order to handle errors from server properly, you have to catch them in the subcribe() method of the Observable returned by http.post from Rxjs:
this.http.post("http://localhost:3003/login/authenticate", this.authenticateObj)
.subscribe(
(res: Response) => {
// code when no error...
},
err => {
// error handling...
},
() => {
// finally...
}
);
IMO Bad request is an incorrect response by your server for incorrect username/password combination. You can return a "401" or a "200" itself depending on your requirement.
Now if you want the error not to appear in the console then add an error callback in your subscribe().
this.http.post("http://localhost:3003/login/authenticate", this.authenticateObj)
...
// rest of the code
.subscribe((res: Response) => {
// your code
}, (error) => {
// handle the error here, show some alerts, warnings, etc
console.log(error)
})

Resources