bcrypt.compare cb is not a function error - javascript

I'm using passport-local and I've already hashed my passwords in my mongo database. I can't figure out why my bcrypt.compare() isn't working correctly. It says 'cb is not a function' but it is. I just saved the callback as a variable in the same file instead of saving it in my User schema. Anyone ran across this problem before or see any errors in my code??
passport.use(new LocalStrategy((username, password, done) => {
User.findOne({ username: username }).exec().then((user, err) => {
if (err) return done(err)
if (!user) return done(null, false, { message: 'Incorrect username.' })
const comparePassword = function (candidatePassword, hashedPassword, cb) {
bcrypt.compare(candidatePassword, hashedPassword, function (err, isMatch) {
if (err) return cb(err)
return cb(null, isMatch)
})
}
comparePassword(password, user.password, function (err, isMatch) {
if (err) return done(err)
if (!isMatch) return done(null, false, { message: 'Incorrect password.' })
return done(null, user)
})
})
}))

So after hours of struggling with bcrypt.compare, I just decided to clear out my database and create new users from scratch. I ended up using bcrypt.compareSync() and it finally verified my passwords! So make sure you have all of your methods defined on your model BEFORE you add users/whatever to your database. I thought I had already added the compare function but I guess I was wrong. Thanks for all of your help!

I also had the same error, just reinstall npm and bcrypt, be careful! see what version of node you are working that is also important. Regards

I encountered something like this before. It has to do with async handling and the fact that all your code is already in the .then() handler of a promise (user.findOne()). It's generally not a good idea to mix promises and the callback pattern.
What I ended up doing is wrapping my comparePassword function in a promise and then including it in the promise chain. My code was quite different, but in your case it would look something like this:
passport.use(new LocalStrategy((username, password, done) => {
function comparePassword(candidatePassword, hashedPassword) {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, hashedPassword,
(err, isMatch) => {
if (err) return reject(err);
else if (!isMatch) reject(new Error('Incorrect Password'));
else resolve();
});
});
})
User.findOne({ username: username }).exec()
.then((user, err) => {
if (err) return done(err)
if (!user) return done(null, false, { message: 'Incorrect username.' })
return comparePassword(password, user.password)
})
.then(/*do stuff if password is a match*/)
.catch(/*do stuff iff not a match*/)
}))
You could also try to just
return comparePassword(password, user.password, function (err, isMatch) {
at the end of your .then(), and I'd declare comparePassword outside of the .then() like in my code above.

The code looks alright to me. Eventhough I didn't test it.
Does your password comparison has to be aSync? Have you considered using bcrypt.compareSync?
Example:
MyPasswordTool.prototype.validateHashedPassword = function(challlenger, hashedPassword) {
return bcrypt.compareSync(challlenger, hashedPassword);
};

Related

done() vs return done()

I was reading the docs for passport and I noticed that with serialize() and deserialize() done() is called with out being returned.
However when setting up a new strategy using passport.use() in the callback function return done() is used.
Is this something that needs to be understood or just copied from the docs?
http://www.passportjs.org/docs/
From the docs:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: 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);
});
}
));
return done() will cause the function to stop executing immediately. This means that any other lines of code after that line inside the function will be ignored and not evaluated.
done() not preceded by return, however, will not cause the function to stop executing. This means that any other lines of code after that line inside the function will be evaluated.
If you take a look at this passport.use() example (from the Passport docs), you'll see there is reachable code after the first three return done() statements, and you would want the function to exit immediately as soon as done() is called the first time to make sure none of the following instructions are evaluated:
passport.use(new BasicStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.validPassword(password)) { return done(null, false); }
// The following line is the success case. We do not want to execute it
// if there was an error, a falsy user or a user without a valid
// password. If we removed the return keywords from the previous lines
// of code, the success case would be triggered every time this
// function was called
return done(null, user);
});
}
));
Here I've added two executable snippets to illustrate the difference between done() and `return done(). The snippets are otherwise identical.
done() without return:
const done = console.log
const assessThreatLevel = threatLevel => {
if (threatLevel === 'all good') done('relax :)')
done('launch the missiles!')
}
assessThreatLevel('all good')
`return done():
const done = console.log
const assessThreatLevel = threatLevel => {
if (threatLevel === 'all good') return done('relax :)')
done('launch the missiles!')
}
assessThreatLevel('all good')
As an aside, I have taken to using return done() in most situations for consistency. As far as I'm aware, there's no drawback to using it. It can help you avoid bugs, and the return statement serves as a guarantee and a good visual reminder that the function will exit immediately after that statement is evaluated.

Promise not returning any data for fetch return

I´m building an express router that uses mongoose to access the database. My current problem relies on this piece of code:
app.use("/authreset", (req, res) => {
authenticator
.resetPassword(
req.body.username,
req.body.password,
req.body.token,
req.body.type
)
.then((response, error) => {
if (error) throw new Error(error);
console.log('*****************');
console.log(response);
if (!response) {
res.sendStatus(401);
return;
}
})
.catch(error => {
console.log('*****************');
console.log(error);
if (error) throw new Error(error);
});
});
resetPassword uses the following mongoose call:
return UserModel
.findByIdAndUpdate(user.id, data, { new: true })
.exec();
For some reason, my route is being called and the response is fine (checked on console.log(response) inside promise).
My problem is that the response is never sent back to the client, that times out the fetch call.
Why is my promise not returning data?
Uh, you log the response, but you never send it (or at least respond with a status code)?
Your code should look more like
app.use("/authreset", (req, res) => {
authenticator.resetPassword(
req.body.username,
req.body.password,
req.body.token,
req.body.type
).then(response => {
console.log(response);
if (!response) {
return res.sendStatus(401);
} else {
return res.sendStatus(200); // <<<
}
}, error => {
console.log(error);
return res.sendStatus(500);
});
});
Notice that the then callback never gets called with more than one argument, so that error you were checking for cannot happen. In the catch handler, you should never rethrow an error if it doesn't get handled further down. Also I changed .then(…).catch(…) to the more fitting .then(…, …).

Confused about promises. Do I need to return here?

So I've recently started to learn Promises (Bluebird) and now I'm trying to use them as much as possible, but I'm a bit confused if I need to return promises in this case.
Here I have a Passport LocalStrategy that I made:
passport.use(new LocalStrategy(function(username, password, done) {
users.get(username) // A
.then(function(user) {
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
bcrypt.compare(password, user.password).then(function(result) { // B
if (result) {
return done(null, user);
}
return done(null, false, { message: 'Incorrect password.' });
});
})
.catch(function(err) {
return done(err);
});
}));
users.get(username) on line A uses the pg-promise library to return a promise that will resolve into a user if one is found in the database and to false if the user was not found.
bcrypt.compare on line B uses bcrypt to check if the password and hash match. It returns a promise that will resolve to true or false.
The code works perfectly, I'm just confused if line A and B should return like so
return users.get(username) // A
return bcrypt.compare(password, user.password).then(function(result) { // B
The code works with and without returning the promises.
Is Passport/Node just waiting until it sees return done? Does this mean that this function is synchronous even though everything inside it is async? Normally you would return a promise and then use .then() on it but since LocalStrategy is not using .then() or .catch() I don't have to return anything? Any input is greatly appreciated. Thanks.
Passport does not support Promise that is why you must call done in a callback. You could return users.get(username)but the return value (promise) is never used. Do not forget that you can chain promises like the following :
users.get(username)
.then(function(user) {
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
return bcrypt.compare(password, user.password);
})
.then(function(result) { // B
if (result) {
return done(null, user);
}
return done(null, false, { message: 'Incorrect password.' });
})
.catch(function(err) {
return done(err);
});

Nodejs Q promise catch never called with passport js

I'm using the passport library for node to assist me in user signup. I'm also using the 'Q' promise library to avoid the pyramid of doom as I go through several asynchronous steps.
Everything works fine, until I throw an error from one of the promised steps. I would have assumed execution would drop into the .fail function, where I could handle the error and return out of passport with a failed signup. But for a reason that I don't understand, the .fail function never gets called. Instead, I just get a stackdump in my browser window and in my console.
The controlling code is here:
q.fcall(checkEmailIsFree({'email':email, 'username':username, 'password':password}))
.then(checkUsernameIsFree)
.then(registerUser)
.then(function (user) {
if (user) {
logDebug('REGISTERED: ' + email);
return done(null, user);
}
else {
logDebug('Could not register');
return done(null, false);
}
})
.fail(function (err) {
logError('I never get here');
return done(null, false);
})
.done();
And here's how I'm throwing, from within checkEmailIsFree
var error = new Error('Bad times. Email is in use: ' + email);
throw error;
Is there some overall express / node code somewhere that is set to fast dump out an exception somehow? Why isn't my catch being called? What am I missing?
I think done(onFulfilled, onRejected, onProgress) can help in this case. You can try:
q.fcall(checkEmailIsFree({'email':email, 'username':username, 'password':password}))
.then(checkUsernameIsFree)
.then(registerUser)
.then(function (user) {
if (user) {
logDebug('REGISTERED: ' + email);
return done(null, user);
}
else {
logDebug('Could not register');
return done(null, false);
}
})
.done(undefined, function (err) {
logError('Error!'); // used in case of reject
return done(null, false);
});

Chaining promises with then and catch

I'm using the bluebird Promise library. I'd like to chain promises and catch specific promises errors. Here's what I'm doing :
getSession(sessionId)
.catch(function (err) {
next(new Error('session not found'));
})
.then(function (session) {
return getUser(session.user_id);
})
.catch(function (err) {
next(new Error('user not found'));
})
.then(function (user) {
req.user = user;
next();
});
But if an error is thrown by getSession, the two catch are called, as well as the second then. I'd like to stop the error propagation at the first catch, so that the second catch is only called when getUser throws, and the second then when getUser succeeds. What do?
The promise that is returned by the .catch method will still be resolved with the result of the callback, it doesn't just stop the propagation of the chain. You will either need to branch the chain:
var session = getSession(sessionId);
session.catch(function (err) { next(new Error('session not found')); });
var user = session.get("user_id").then(getUser);
user.catch(function (err) { next(new Error('user not found')); })
user.then(function (user) {
req.user = user;
next();
});
or use the second callback to then:
getSession(sessionId).then(function(session) {
getUser(session.user_id).then(function (user) {
req.user = user;
next();
}, function (err) {
next(new Error('user not found'));
});
}, function (err) {
next(new Error('session not found'));
});
Alternatively, the better way would to just propagate the errors through the chain, and call next only in the very end:
getSession(sessionId).catch(function (err) {
throw new Error('session not found'));
}).then(function(session) {
return getUser(session.user_id).catch(function (err) {
throw new Error('user not found'));
})
}).then(function (user) {
req.user = user;
return null;
}).then(next, next);
Since you're using bluebird for promises, you actually don't need a catch statement after every function. You can chain all your thens together, and then close the whole thing off with a single catch. Something like this:
getSession(sessionId)
.then(function (session) {
return getUser(session.user_id);
})
.then(function (user) {
req.user = user;
next();
})
.catch(function(error){
/* potentially some code for generating an error specific message here */
next(error);
});
Assuming the error messages tell you what the error is, it's still possible to send an error specific message like 'session not found' or 'user not found', but you'll just have to look into the error message to see what it gives you.
Note: I'm sure you probably have a reason for calling next regardless if there's an error or not, but it might be useful to throw in a console.error(error) in the case that you get an error. Alternatively, you could use some other error handling function, whether it's a console.error, or res.send(404), or something of the like.
I am using it like that:
getSession(x)
.then(function (a) {
...
})
.then(function (b) {
if(err){
throw next(new Error('err msg'))
}
...
})
.then(function (c) {
...
})
.catch(next);

Categories

Resources