Callback code not executed - node.js

Here is my code:
socket.on('add user', function (data) {
d('"add user" event');
d(data, true);
debugger;
UserEngine.login({
username: data.username,
password: data.password
}, function(err, user) {
if (err) {
d('Bad Login. Username: ' + data.username);
return;
}
/*
** Code after this comment is never executed
*/
debugger;
d('Login OK: ' + data.username);
socket.username = data.username;
usernames[data.username] = data.username;
++numUsers;
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
return;
});
});
If there is an error in UserEngine.login(...), the If statement before the comment works correctly and the callback returns. But if the method works correctly, the code after the If statement isn't executed.
Why?
Edit:
Here is the code of the UserEngine module:
http://pastebin.com/u2DQJrV3

My guess is that your code is throwing an exception somewhere in your login() method and because much of that code is executed in async callbacks, you may not get any exception info in the console.
Here are several suggestions for debugging this problem:
You need to follow the exact flow through your login() method. If what you say in your question is true, then it isn't calling the callback sometimes and you need to find out why. The simplest way to follow the flow is to insert a uniquely tagged console.log() statement in every branch of the login() method so you can see exactly which way the control flow goes and what is executed and what is not. Once you find that, you can then output various values to see why it goes that way or set an appropriate breakpoint and trace through it.
There also could be an exception of some kind getting thrown in the login() method or in something that it calls. One you get into an async callback, exceptions may not get logged in the console so things could fail silently and the callback could just be skipped without anything showing in the console. If you suspect an exception in a particular place, you can put your own exception handler there and log what the exception is. Remember, each async scope needs its own exception handler - you can't just use one exception handler at the top level. This is a complication of async coding and one reason why using promises instead of plain callbacks is massively more useful because the promise system will catch all async exceptions for you and turn it into a rejected promise with the exception as the reason (so async exceptions don't fail silently).
There is a logic problem in your login() method if it goes does the user.save() branch of code. I've documented that issue below, though I don't think that is your main issue - but it is something to fix.
I'd also suggest you put logging where you call your UserEngine.login() so you are logging ALL possible callback values.
Suggested logging:
UserEngine.login({
username: data.username,
password: data.password
}, function(err, user) {
// =========== Add this ============
console.log("UserEngine.login() callback");
console.log(err, user);
if (err) {
d('Bad Login. Username: ' + data.username);
return;
}
Here's the issue with the user.save() path in your login() method:
In your login() code, as part of the self._verifyToken() function call, you need to change this:
login: function(args, callback) {
/**
* username [String]
* password [String]
*/
var self = this;
if (!args.username || !args.password) {
return callback(Error.genObj(Error.code.MISSING_PARAMS));
}
User.findOne({
username: args.username
}, function(err, user) {
console.log('[Debug] In User.findOne(...) Callback;');
if (err) {
return callback(Error.genObj(Error.code.INTERNAL));
}
if (!user) {
return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
}
if (self._generateHash({ password: args.password, salt: user.salt }) != user.password) {
return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
}
self._verifyToken({
token: user.token,
username: args.username,
key: Config.tokenKey
}, function(err) {
if (err) {
var token = self._generateToken({ username: args.username, key: Config.key });
user.token = token;
user.save(function(err) {
if (err) {
return callback(Error.genObj(Error.code.INTERNAL));
}
return callback(null, user);
});
}
return callback(null, user);
});
});
},
To this:
login: function(args, callback) {
/**
* username [String]
* password [String]
*/
var self = this;
if (!args.username || !args.password) {
return callback(Error.genObj(Error.code.MISSING_PARAMS));
}
User.findOne({
username: args.username
}, function(err, user) {
console.log('[Debug] In User.findOne(...) Callback;');
if (err) {
return callback(Error.genObj(Error.code.INTERNAL));
}
if (!user) {
return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
}
if (self._generateHash({ password: args.password, salt: user.salt }) != user.password) {
return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
}
self._verifyToken({
token: user.token,
username: args.username,
key: Config.tokenKey
}, function(err) {
if (err) {
var token = self._generateToken({ username: args.username, key: Config.key });
user.token = token;
user.save(function(err) {
if (err) {
return callback(Error.genObj(Error.code.INTERNAL));
}
return callback(null, user);
});
} else {
// ======== put this in an else clause ==========
return callback(null, user);
}
});
});
},
The issue is that if you get an error from verifyToken(), then it will start user.save(), but since that's async, it will continue on and execute return callback(null, user) before the user.save() operation is done and then it will call the callback again when user.save() is done.

Related

MongoDb findOne query results in error - even if data is found

the below is my controller function
exports.validateUsername = async (uName) => {
console.log("inside validate username");
await User.findOne({ username: "sab2" }).then(function (err, user) {
if (err) {
console.log("inside err");
console.log("error");
console.log(err);
return true;
} else {
console.log("inside user found");
console.log("user");
console.log(user);
return false;
}
});
};
I have record in my "user" collection with username ="sab2". But still , the promise function results in err, and goes inside if(err).
But when I do console.log(err) I get the actual user data "sab2" object.
I have a doubt if the function syntax is function(data,err).
Error object printed
Please suggest a solution.
The then() on a findOne does not return a error, I would rewrite like this:
User.findOne({ username: "sab2" }, function(err, user) {
if (err) {
console.log("inside err");
console.log("error");
console.log(err);
return true;
} else {
console.log("inside user found");
console.log("user");
console.log(user);
return false;
}
});
then do not return error. Do something like this to catch error
await User.findOne({ username: "sab2" }).then((user) => {
console.log(user)
}).catch(error=>console.log(error))
or use callback. See here

Using node.js 'util' to promisify is returning an error

I'm trying to create a function in a file to return a promis, which I will call form another file. I'm trying to use the 'util.promisify' to wrap the function, but I'm getting an error. Here is the code and the error:
from my 'checkEmail.js':
const Profile = require('../../models/profile');
const util = require('util');
var exports = module.exports = {};
exports.findEmail = util.promisify(checkEmail());
function checkEmail (email) {
Profile.findOne({ 'emails': { $elemMatch: { email_address: email } } }, (err, userEmail) => {
let conclusion = false;
if (err) {
console.log('Error in looking up an existing email');
} else {
if (userEmail) {
console.log('We found an existing owner for email: ' + email);
conclusion = true;
}
}
return conclusion;
})
}
Calling it on 'profile.js':
router.route('/addemail/:id')
// ADD EMAILS
.put(function (req, res) {
Profile.findOne({ 'owner_id': req.params.id }, function (err, profile) {
if (err)
res.send(err);
EmailCheck.findEmail(req.body.email_address).then((data)=>{
console.log('The answer is: ', data);
});
profile.emails.push({
email_type: req.body.email_type,
email_address: req.body.email_address
})
profile.save(function (err) {
if (err)
res.send(err);
res.json(profile);
});
});
});
The error I'm getting is:
Config for: http://localhost:3000
internal/util.js:272
throw new ERR_INVALID_ARG_TYPE('original', 'Function', original);
Any help would be appreciated.
In order to promisify the function that you pass to util.promisify must:
Take a function following the common error-first callback style, i.e.
taking a (err, value) => callback as the last argument, and returns a version that returns promise
So you can either promisify Profile.findOne, or pass a callback as the last argument to checkEmail
function checkEmail (email, callback) {
Profile.findOne({ 'emails': { $elemMatch: { email_address: email } } }, (err, userEmail) => {
let conclusion = false;
if (err)
return callback(new Error('Error in looking up an existing email'));
if (userEmail) {
console.log('We found an existing owner for email: ' + email);
conclusion = true;
}
return callback(null, conclusion);
})
}
And then you should call it like this:
exports.findEmail = util.promisify(checkEmail);
Otherwise you're passing to .promisify the returned value of checkEmail which is not a function following the style commented above.
You have typo, use util.promisify(checkEmail) instead, parentheses are redundant

Node.js - Check if user exists

I'm using NodeJS and passport to let users create an account before they can see results of a quiz they've just taken. My challenge is I need to confirm the username is available before the page refreshes because the user will lose their results if this happens.
Again: I need to verify the username is not taken prior to refreshing.
I think I'm close but it is not working. How would I change my code to handle this challenge?
Currently if the user name is taken it returns an error on trying to create an account and the user ends up on the /failpage as shown below.
app.post('/quiz', usernameToLowerCase, emailToLowerCase, function(req, res) {
User.findOne({
username: req.body.username
}, function(err, user) {
if (err) {
alert(err)
if (user) {
alert('this username is already taken. Please choose another.')
console.log('there was a user');
return false;
}
}
});
var user = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password,
})
user.save(function(err) {
console.log('this is the problem' + ' ' + err)
if (err) {
return res.redirect('/failpage')
}
req.logIn(user, function(err) {
if (err) {
console.log(err);
}
console.log('all looks good')
res.redirect('/results');
});
});
});
Solved it with this if anyone else is trying to do the same thing:
in app.js
app.get('/usercheck', function(req, res) {
User.findOne({username: req.query.username}, function(err, user){
if(err) {
console.log(err);
}
var message;
if(user) {
console.log(user)
message = "user exists";
console.log(message)
} else {
message= "user doesn't exist";
console.log(message)
}
res.json({message: message});
});
});
In js
$('#usercheck').on('change', function() {
$.get('/usercheck?username='+$('#usernameValue').val().toLowerCase(), function(response) {
$('#usernameResponseHidden').text(response.message)
if ($('#usernameResponseHidden').html() === "user exists"){
$('#usernameResponse').text('That username is taken. Please pick another')
}
To solve your problem I think you need to routes. At least a app.get('/quiz') which returns a boolean on if the user exists or not. The section User.findOne can be sent in that route instead. You just need to make a request using ajax when he looses focus of the username field of your form, and display a notification if the name is available or not.

nodejs inherit function inside a function

im trying to inherit a function inside one, but im not sure how.
function register(Username, Password, callback)
{
var result;
UserModel.findOne({username: Username}, function(error, data)
{
if(error)
console.log(error);
if(data)
result = 'already exist';
mongoose.connection.close();
if(!data)
{
var user = new UseModel(
{
username: Username,
password: Password
});
user.save(function(error)
{
if(error)
{
console.log(error);
result = 'Error';
}
result = 'success';
mongoose.connection.close();
});
}
});
callback;
}
i thought that making a callback, i would be able to set a custom function in there.
i've seen someplaces that people do inherit functions inside another one, but i dont find them anymore and im trying to do them, for this code im saving a record in mongo.
so lets just say, in the other code, im calling this function with first 2 parameters, and the third would do the function i want it to do depending of the result, just like this.
this.register('myname', 'mypassword', function(
{
if(result != 'error')
{
response.render('register',
{
'Title': Title,
'result': result
});
}
}));
im not sure if the inherit is like this. but this is what im trying to do, im learning js with node so please sorry about my unexperience.
PD: im using express, swig, body-parser and mongoose modules for node.js
Here's how your register() function might look:
function register(Username, Password, callback)
{
UserModel.findOne({username: Username}, function(error, data)
{
if(error)
return callback(error);
if(data)
return callback(null, 'User already exists');
var user = new UseModel(
{
username: Username,
password: Password
});
user.save(function(error)
{
if(error)
return callback(error);
callback(null, 'Success');
});
});
}
Here's how it would be used:
this.register('myname', 'mypassword', function(error, result)
{
if (error)
return console.error(error); // do something better here
response.render('register',
{
'Title': Title,
'result': result
});
});

Why is my node js code able to POST a login form to be matched from mongodb?

I am using node.js I already can post from a signup html page. However the code below
exports.login = function (req, res, next) {
if (req.body && req.body.email && req.body.password) {
var userLogin = new User ({
email: req.body.email,
password: req.body.password
});
userLogin.findOne(function(err) {
if (!err) {
res.redirect('/about.html');
} else {
res.redirect('http://google.com');
next(err);
}
});
} else {
next(new Error('Incorrect POST'));
}
};
The problem I am having is that the userLogin.findOne is not working as it says findOne is undefined.
The model.js file that this is linking to is:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs'),
SALT_WORK_FACTOR = 10;
// these values can be whatever you want - we're defaulting to a
// max of 5 attempts, resulting in a 2 hour lock
MAX_LOGIN_ATTEMPTS = 5,
LOCK_TIME = 2 * 60 * 60 * 1000;
var UserSchema = new Schema({
email: { type: String, required: true, lowercase:true, index: { unique: true } },
password: { type: String, required: true },
firstName: {type: String, required: true},
lastName: {type: String, required: true},
phone: {type: Number, required: true},
birthday: {type: Date, required: true},
loginAttempts: { type: Number, required: true, default: 0 },
lockUntil: { type: Number }
});
UserSchema.virtual('isLocked').get(function() {
// check for a future lockUntil timestamp
return !!(this.lockUntil && this.lockUntil > Date.now());
});
//password hashing middleware
UserSchema.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 along with 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();
});
});
});
//password verification
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
UserSchema.methods.incLoginAttempts = function(cb) {
// if we have a previous lock that has expired, restart at 1
if (this.lockUntil && this.lockUntil < Date.now()) {
return this.update({
$set: { loginAttempts: 1 },
$unset: { lockUntil: 1 }
}, cb);
}
// otherwise we're incrementing
var updates = { $inc: { loginAttempts: 1 } };
// lock the account if we've reached max attempts and it's not locked already
if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked) {
updates.$set = { lockUntil: Date.now() + LOCK_TIME };
}
return this.update(updates, cb);
};
// expose enum on the model, and provide an internal convenience reference
var reasons = UserSchema.statics.failedLogin = {
NOT_FOUND: 0,
PASSWORD_INCORRECT: 1,
MAX_ATTEMPTS: 2
};
UserSchema.statics.getAuthenticated = function(email, password, cb) {
this.findOne({ email: email }, function(err, user) {
if (err) return cb(err);
// make sure the user exists
if (!user) {
return cb(null, null, reasons.NOT_FOUND);
}
// check if the account is currently locked
if (user.isLocked) {
// just increment login attempts if account is already locked
return user.incLoginAttempts(function(err) {
if (err) return cb(err);
return cb(null, null, reasons.MAX_ATTEMPTS);
});
}
// test for a matching password
user.comparePassword(password, function(err, isMatch) {
if (err) return cb(err);
// check if the password was a match
if (isMatch) {
// if there's no lock or failed attempts, just return the user
if (!user.loginAttempts && !user.lockUntil) return cb(null, user);
// reset attempts and lock info
var updates = {
$set: { loginAttempts: 0 },
$unset: { lockUntil: 1 }
};
return user.update(updates, function(err) {
if (err) return cb(err);
return cb(null, user);
});
}
// password is incorrect, so increment login attempts before responding
user.incLoginAttempts(function(err) {
if (err) return cb(err);
return cb(null, null, reasons.PASSWORD_INCORRECT);
});
});
});
};
module.exports = mongoose.model('User', UserSchema);
In your code, userLogin is an instance of the User model which means you've created a document. As documentation for mongoose queries states, queries are handled using 'static helper methods' which means they aren't available on an instance of a model (i.e. on a document).
I think you'd probably want your code to look more like this where userLogin is an object that holds your conditions for the query and then you could use the User model's .findOne method to execute the query.
var userLogin = {
email: req.body.email,
password: req.body.password
};
User.findOne(userLogin, function(err) {
if (!err) {
res.redirect('/about.html');
} else {
res.redirect('http://google.com');
next(err);
}
});
Edit: OK, so the above answered the question about why findOne was undefined.
The second question asked is "why doesn't this authenticate the user?"
The reason the code is redirecting to (I assume) the '/about.html' page is because that's exactly what the code does...as written.
To authenticate (and we're technically starting a new answer to an originally unasked question): you need to call the UserSchema.statics.getAuthenticated method that is defined in modules.js. That would need code like this (slightly modified from the tutorial where most of this code originated):
User.getAuthenticated('<valid_email>', '<valid_password>', function(err, user, reason) {
if (err) throw err;
if (user) {
// handle login success
// note, handling success is more than a res.redirect call
// if you need to deal with session, state, cookies, etc...
return;
}
// otherwise we can determine why we failed
var reasons = User.failedLogin;
switch (reason) {
case reasons.NOT_FOUND:
case reasons.PASSWORD_INCORRECT:
// note: these cases are usually treated the same - don't tell
// the user *why* the login failed, only that it did
break;
case reasons.MAX_ATTEMPTS:
// send email or otherwise notify user that account is
// temporarily locked
break;
}
});
As a side-node, I'd suggest you look into everyauth or passport.js as modules that can do much of this for you. At that point, your main concern will be writing code for user CRUD while the modules handle sessions, cookies, serialization/deserialization and so on for you. This is doubly true if you have any plans to include OAUTH logins via google, facebook, et al.

Resources