I've looked through the other issues with bcrypt.compare on GitHub and none of the solutions have worked for me. It always fails on console.log("failed 3") inside bcrypt.compare()
I've tried switching the .then() instead of using a callback with bcrypt.compare as suggested by another post but that hasn't help. Any help would be greatly appreciated!
Below is a copy of my code and summary of versions being used:
Node v8.12.0
Express 4.16.0
bcrypt 3.0.3
jsonwebtoken 8.4.0
mongoose 5.4.1
Bcrypt Hash (Password Hashing)
function saveUserData(req, res, next, userSignUpInfo, info){
bcrypt.hash(req.body.email, 10, (err, hash) =>{
if (err){
return res.status(500).json({
error: err
})
} else {
console.log('inside test route')
console.log('req.body.fnUserName', userSignUpInfo.fnUserName)
const userData = new UserData({
fnUserName : userSignUpInfo.fnUserName,
password : hash,
email : req.body.email,
verify: userSignUpInfo.verify,
createAccountDate: userSignUpInfo.createAccountDate,
userId : userSignUpInfo.userId,
friends: null,
online: null
})
userData.save()
.then(result => {
console.log('result from MongoDB Cloud', result);
saveApiData(info, userSignUpInfo, res);
})
.catch(err => console.log('error from MongoDB Cloud', err));
}
})
}
Bcrypt Compare (Auth User)
router.post('/login', (req, res, next) => {
UserData.find({email: req.body.email})
.exec()
.then(user => {
if(user.length < 1) {
console.log("failed 1")
return res.status(401).json({
message: 'Authentication Failed'
});
}
console.log('user[0].password', user[0].password)
console.log(' user[0].password', user[0].password)
console.log(' req.body.password', req.body.password)
bcrypt.compare(req.body.password,user[0].password).then(function(err, result) {
if (err) {
console.log("failed 1")
return res.status(401).json({
message: 'Authentication Failed'
});
}
if (result) {
const token = jwt.sign(
{
email: user[0].email,
userId: user[0].userId
},
process.env.JWT_KEY,
{
expiresIn: "1h" // he suggested one hour
}
);
console.log("failed 2")
return res.status(200).json({
message: 'Authentication Successful',
token: token
})
} else {
console.log("failed 3")
res.status(401).json({
message: 'Authentication Failed'
})
}
})
})
.catch(err => {
console.log('err in login', err);
res.status(500).json({
error: err,
message: 'error logging in'
})
})
});
Usually, password is saved as hash in the database. Also, provide adequate length for saving hashes into database.(atleast 60 varchars). To do so,
schema.pre("save", function (next) {
bcrypt.hash(this.password, 10, (err, hash) => {
this.password = hash;
next();
});
});
Then, plain password is compared against the hash from database.
bcrypt.hash('mypassword', 10, function(err, hash) {
if (err) { throw (err); }
bcrypt.compare('mypassword', hash, function(err, result) {
if (err) { throw (err); }
console.log(result);
});
});
result will always be undefined since promises return a single value and errors are simply thrown in the catch phrase. So basically, in your code, err will contain the actual result.
What your code should look like is the following:
bcrypt.compare(req.body.password,user[0].password).then((result)=>{
if(result){
console.log("authentication successful")
// do stuff
} else {
console.log("authentication failed. Password doesn't match")
// do other stuff
}
})
.catch((err)=>console.error(err))
It looks like you don't return your res.status inside the
else { console.log("failed 3")
block like you do in the failed 2 and failed 1 blocks.
Related
I am trying to implement the validation of password change and the issue I have is that I am not getting errorMessage back from the server in case of an error. I have managed to get it work and send back response after the password was updated. Also, I can console.log the error message on the back end but it's not returning an object with errorMessage to the front end.
if (!currentPassword) {
console.log("no current password");
return res
.status(400)
.json({ errorMessage: "Please confirm your current password" });
}
On the front code looks like this:
handleSubmit = (event) => {
event.preventDefault();
const authorization = localStorage.getItem("accessToken");
axios
.put(
`${process.env.REACT_APP_SERVER_URL}/settings/password`,
this.state.user,
{
headers: {
authorization,
},
}
)
.then((res) => {
if (res.errorMessage) {
console.log(res, "Unsuccessful password updated");
} else {
console.log("updating - res:", res);
this.setState({
user: res.data,
});
}
})
.catch((err) => {
console.log(err, "ERROR");
});
};
Everytime there is an error, I am not consol login the actual erroMessage but it is being catched in catch. What is the cause of that?
Thanks
Not a direct res its available under res.data.
Response schema of axios
use
if (res.data.errorMessage) {
instead of
if (res.errorMessage) {
For better understanding you need to console.log(res). Then you could understand the structure of the response
router.put("/password", isLoggedIn, (req, res, next) => {
const { currentPassword, newPassword, newPasswordConfirm } = req.body;
User.findById(req.user._id)
.then((user) => {
bcrypt.compare(currentPassword, user.password).then((isSamePassword) => {
if (!isSamePassword) {
console.log(
"Incorrect current password. To change your password try again!"
);
return res.status(400).json({
errorMessage:
"Incorrect current password. To change your password try again!",
});
}
return bcrypt
.genSalt(saltRounds)
.then((salt) => bcrypt.hash(newPassword, salt))
.then((hashedPassword) => {
User.findByIdAndUpdate(
req.user._id,
{ password: hashedPassword },
{ new: true }
)
.then((user) => {
console.log("user's password successfully changed");
res.status(200).json(user);
})
.catch((err) => {
res.status(500).json({ errorMessage: err.message });
});
})
.catch((err) => {
res.status(500).json({ errorMessage: err.message });
});
});
})
.catch((err) => {
console.log(err);
res.status(500).json({ errorMessage: err.message });
});
});
Im currently writing a RESTful API for a webservice but im having trouble. Im trying to delete an mail, but first i want to check if the mail even exists. My problem is that it doesn't check if mail is null and doesn't respond with a 404. Im working with express and mongoose
router.delete('/:id', (req, res) => {
const { id } = req.params;
Mail.findById(id)
.exec()
.then((mail) => {
if (!mail) {
console.log(mail) // returns null
return res.status(404);
}
})
.then(
Mail.deleteOne({ _id: id })
.exec()
.then(() => {
res.status(200).json({
message: 'Mail deleted',
});
})
.catch((err) => {
res.status(500).json({ error: err });
})
);
});
I think you have to do the the deletion part of the code inside the first then block as an else statement. You are not returning anything that the next then block can use.
you could do:
Mail.findById(id)
.exec()
.then((mail) => {
if (!mail) {
console.log(mail) // returns null
return res.status(404).send() //need to send response;
}
Mail.deleteOne({ _id: id })
.exec()
.then(() => {
res.status(200).json({
message: 'Mail deleted',
});
})
}).catch((err) => {
res.status(500).json({ error: err });
})
PRO TIP: if you don't know it, learn async await. Code will look much cleaner!
Then it would look like this:
router.delete('/:id', async (req, res) => {
const { id } = req.params;
try {
const mail = await Mail.findById(id);
if(!mail) {
return res.status(404).send();
}
await Mail.deleteOne({_id: id});
res.status(200).json({
message: 'Mail deleted',
});
} catch(e) {
res.status(500).json({ error: err });
}
I'm following a course about node.js on Udemy which is kinda outdated and came across these errors which I'm unable to find a solution for.
What I tried:
using next();
adding return res inside all if statements
Can someone help me fix these? I would greatly appreciate it!
Thanks in advance!
Username exists error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:526:11)
at ServerResponse.header (C:\Users\Documents\projects\chat-app\chat-app-backend\node_modules\express\lib\response.js:771:10) at ServerResponse.send (C:\Users\Documents\projects\chat-app\chat-app-backend\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\Documents\projects\chat-app\chat-app-backend\node_modules\express\lib\response.js:267:15)
at C:\Users\Documents\projects\chat-app\chat-app-backend\controllers\auth.js:38:56
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
module.exports = {
CreateUser(req, res) {
const schema = Joi.object().keys({
username: Joi.string().min(5).max(15).required(),
email: Joi.string().email().required(),
password: Joi.string().min(5).required()
});
const {error, value} = Joi.validate(req.body, schema);
if (error && error.details) {
return res.status(HttpStatus.BAD_REQUEST).json({message: error.details});
}
async function EmailExists() {
return await User.findOne({email: Helpers.lowerCase(req.body.email)}) != undefined;
}
async function UsernameExists() {
return await User.findOne({username: Helpers.firstLetterUppercase(req.body.username)});
}
EmailExists().then(exists => {
if (exists) {
return res.status(HttpStatus.CONFLICT).json({message: 'Email already exists'});
}
}).catch((err) => console.log('Email exists error: ', err));
UsernameExists().then(exists => {
if (exists) {
return res.status(HttpStatus.CONFLICT).json({message: 'Username already exists'}) != undefined;
}
}).catch((err) => console.log('Username exists error: ', err));
return BCrypt.hash(value.password, 10, (error, hash) => {
if (error) {
return res.status(HttpStatus.BAD_REQUEST).json({message: 'Error hashing password'});
}
const body = {
username: Helpers.firstLetterUppercase(value.username),
email: Helpers.lowerCase(value.email),
password: hash
};
User.create(body).then((user) => {
res.status(HttpStatus.CREATED).json({message: 'User created successfully'});
}).catch((err) => {
res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({message: 'Something went wrong. Could not save user'});
});
});
}
}
You're executing some promise and don't wait for the answer before executing the next code....
There are many ways to handle this, this next code is just one way...
const hash = () => BCrypt.hash(value.password, 10, (error, hash) => {
if (error) {
return res.status(HttpStatus.BAD_REQUEST).json({message: 'Error hashing password'});
}
const body = {
username: Helpers.firstLetterUppercase(value.username),
email: Helpers.lowerCase(value.email),
password: hash
};
User.create(body).then((user) => {
res.status(HttpStatus.CREATED).json({message: 'User created successfully'});
}).catch((err) => {
res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({message: 'Something went wrong. Could not save user'});
});
});
EmailExists().then(exists => {
if (exists) {
return res.status(HttpStatus.CONFLICT).json({message: 'Email already exists'});
}
UsernameExists().then(exists => {
if (exists) {
return res.status(HttpStatus.CONFLICT).json({message: 'Username already exists'}) != undefined;
}
return hash();
}).catch((err) => console.log('Username exists error: ', err));
}).catch((err) => console.log('Email exists error: ', err));
My app crashes when an empty value is passed in query.
db.collection.update({_id:1234},{ $pull: { "": {code:321} } })
Error :
UnhandledPromiseRejectionWarning: MongoError: An empty update path is not valid.
How can I handle this situation without crashing the app.
Below is my code.
{
try {
const db = client.db(dbName);
db.collection(cName).updateOne({ _id: id }, { $pull: query }).then((err, result) => {
if (err) {
callBack(err);
} else {
callBack(null, result);
}
});
client.close();
}
catch (err) {
callBack({
error: 'Unable to process the request',
errorMessage: err
})
}
}
You can validate your query by simply adding if condition before passing it to the MongoDB as below:
{
try {
if(query["field"]){ // Name of field from which you wants to pull
const db = client.db(dbName);
db.collection(cName).updateOne({ _id: id }, { $pull: query }).then((err, result) => {
if (err) {
callBack(err);
} else {
callBack(null, result);
}
});
client.close();
}else{
/** QUERY NOT FOUND OR INCORRECT QUERY PASSED **/
}
}
catch (err) {
callBack({
error: 'Unable to process the request',
errorMessage: err
})
}
}
Currently, I am having trouble with promises in my 'Javascript' code. It keeps throwing "TypeError: res.status(...).json(...).catch is not a function", and i'm guessing my promises are wrong somewhere along the line of code.
This is what I have so far:
route.js
route.post('/login', function(req, res) {
log.login(req,res).then((post)=>{
res.status(200).json({message: post})
.catch((error)=>{
res.status(400).json({message: error})
})
})
});
and login.js
function login(req,res){
console.log('here', req.body.email, req.body.password)
if (!req.body.email || !req.body.password) {
return Promise.resolve({success: false, msg: 'Please pass email and password.'});
} else {
return Promise.resolve(User.findOne({
'local.email': req.body.email
})).exec().then((user)=> {
if (!user) {
return Promise.reject({success:false, msg: 'Authentication failed. User not found'}); //res.send({success: false, msg: 'Authentication failed. User not found.'});
} else {
// check if password matches
if(user.validPassword(req.body.password)) {
// if user is found and password is right create a token
var token = jwt.sign(user.id, config.secret);
// return the information including token as JSON
return Promise.resolve({success: true, token: 'JWT ' + token});
} else {
return Promise.reject({success: false, msg: 'Authentication failed. Wrong password.'});
}
}
}).catch((errors)=>{
return ({message: "Could not propose login"});
})
}
}
module.exports = {
login
}
I believe that you've just missed }), the fixed code:
route.post('/login', function(req, res) {
log.login(req,res).then((post) => {
res.status(200).json({message: post})
})
.catch((error) => {
res.status(400).json({message: error})
})
})
});