Exiting from post route if middleware condition fails and not continue to execute the function - node.js

I've had an issue I've been racking my brain (and my googling fingers) with and it's in regard to middleware and express.js.
What I'm essentially trying to do is check if an email is currently in use in my MongoDB database (the check works fine) and if the email address exists, to not continue with my post route and create an account. My flash message works just fine, however my code after doesn't prevent the account from being created still.
I know I can just add the email to an index in my User Schema and call it a day, but it's bugging me not knowing how to do it this other way.
Is it possible, for lack of better coding knowledge, to just say, if email exists, then exit entire router.post, tell user email is in use - without then going on and executing the function(req, res) which creates the account regardless of the email error?
Here is my code for the middleware I'm using to check if the email is already being used.
middlewareObj.checkEmailExist = function(req, res, next){
//Converts user entered email to lowercase
var lowercaseEmail = req.body.email.toLowerCase();
//looks for user entered email in database
User.find({"email": lowercaseEmail}, function(err, user){
if(user.length!=0) {
req.flash("error", "Email already exists, please enter a different email address");
return res.redirect("/register");
}
});
return next();
};
And here is the code for the /register POST route:
router.post("/register", middleware.usernameToLowerCase, middleware.checkSignupForm, middleware.checkEmailExist, function(req, res){
var newUser = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
username: req.body.username
});
User.register(newUser, req.body.password, function(err, user){
if(err){
//For Standard error message or if not included in specific messages below
console.log("error", err.message);
return res.redirect("/register");
}
passport.authenticate("local")(req, res, function(){
req.flash("success", "Welcome To Our Community " + user.firstName + "." + "Your Username Is: " + user.username);
res.redirect("/featured");
});
});
});
You can ignore the other middleware being called prior, that is just for formatting for my database.
I've tried doing the return next(err); but it still just creates the account while also giving me a "Can't set headers after they are sent" error due to the rest of the function being called.
This is my first post, so hopefully I didn't make things too confusing. Let me know if you need additional info/context and I'd be happy to provide.
Thanks in advance!

In your middleware function you are looking up the database which is asynchronous. In the meantime you have gone on to call return next() before the callback is called.
Try to move the return next() in the middleware to and else block of if(user.length!=0) in User.find

Related

How do I check for an existing value in MongoDB with Axios? [duplicate]

This question already has answers here:
How to query MongoDB to test if an item exists?
(10 answers)
Closed 3 years ago.
I'm learning MERN stack development and I'm making a practice app with user login/registration. I have the Node server and MongoDB up and running, and I'm able to register new users, update usernames & passwords, retrieve a list of users, and retrieve info about a single user. I'm doing this using post/get requests to localhost:4000/credentials-test/etc with Postman (I haven't actually connected the front end yet).
I'm able to get info on a single user with the following code in my server.js file:
credsRoutes.route('/user/:id').get(function(req, res) {
let id = req.params.id;
User.findById(id, function(err, user) {
res.json(user);
});
});
I figured I'd be able to do something similar to check if a username already exists (to prevent duplicate usernames on registration or username changing), with the following code:
credsRoutes.route('/check-user/:username').get(function(req, res) {
let username = req.params.username;
User.find(username, function(err, user) {
if (!user)
res.json('User not found :(');
else
res.json('User found! Details:');
res.json(user);
});
});
But the response from localhost:4000/credentials-test/check-username/testuser is always User not found :(, even when the username definitely belongs to an existing user.
Any ideas why this might be happening and how I can implement a working solution?
You need to pass a query object into the Mongoose model. Also, it's wise to return out of the function when you call res.json() because the rest of the function could still run, .end() is a method that will explicitly end the client's request.
try this:
credsRoutes.route("/check-username/:username").get(function(req, res) {
const username = req.params.username;
User.findOne({ username }, function(err, user) {
if (!user) {
return res.json("User not found :(").end();
}
return res.json(`User found! Details: ${user}`).end();
});
});
`

Why is passport.authenticate needed in a registration?

I'm learning Passport, using local strategy and Mongoose, through passport-local-mongoose plugin.
It makes sense to me in a /login for example, but I don't understand why passport.authenticate is needed in a registration, right after it having already taken place...
Can anyone explain me, please? Also, what if it fails?
The following code was taken from a tutorial, but I have found similar constructions all over.
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username }),
req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
if (req.body.firstname) {
user.firstname = req.body.firstname;
}
if (req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
The password isn't used to authenticated the user inside this snipped.
Call User.register
Creates a new User Object with the username, and needs the password to do
some magic with it. Probably build a hash which gets added to your 'user' object.
Call user.save
Saves this 'user' object inside your Storage, if this is successful the user gets authenticated, and returns HTTP 200 which ends the registration process.
Error Handling isn't implemented in this save method, for that you will have an exception on error.
Hope this helps to understand, your snippet.
To use your /login method your new user can use his username and password which he gave to you during the registration process.

Stay on same page when error occur in Node.js

I am new in Node.js. Please give me some solutions regarding this.
I am just created the registration form and posting the page, And I have used Mongoose validation. How to stay on the same page from where I am posting the request, because its showing the posted page with error message.
router.post("/formpost", upload.array('myFile', 12), function(req, res, next){
var user1 = new User({
firstname:req.body.first_name,
lastname: req.body.last_name,
email: req.body.email,
});
user1.save(function(err){
if (err) {
res.send(errMessage);
}
else
{
res.send("Success");
}
});
});
Or if I am using,
return next(new Error(errMessage));
then its showing the complete error message on the page. but still its on the posted page
Use res.redirect('back'); whenever you find some error!

Check for existing user using Mongoose

I'm trying to write a middleware function that (when a POST request is made with a username/password) checks to see if the user being created already exists in the database. I don't know if I'm doing this properly though.
User.find({ username: req.body.username }) returns an object which contains (or does not contain) the user if it exists...but how to properly return to exit if a user under the same username is found? Whenever I test this with Mocha, res.body.msg comes up as undefined.
Code:
module.exports = exports = function(req, res, next) {
User.find({ username: req.body.username }, (err, user) => {
if (err) return handleDBError(err, res);
if (user) return res.status(200).json({ msg: 'an account with this username already exists' });
});
next();
};
User Schema:
var userSchema = new mongoose.Schema({
username: String,
authentication: {
email: String,
password: String
}
});
give it a try very initial create a function to get the user response
function findUser(arg, callback) {
/* write your query here */
return callback(pass response here)
}
And then use it where you want
findUser(arg,function(callbackResponse) { /*do something*/ })
Since nodejs is asynchronous, chances are that the response is being sent after you are trying to read it. Make sure to keep the reading process waiting untill response is sent. I personaly use passport for handling that.

Node - Passport Auth - Authed Post Route hangs on form submission

This is a weird one. Im Passport's 'Local Strategy' for my express app and i'm running into an odd issue.
Essentially, I have three routes. Each have an auth check in place.
app.get('/admin', authenticatedOrNot, adminRoute.index);
app.get('/admin/new', authenticatedOrNot, adminRoute.newpost);
app.post('/admin/new', authenticatedOrNot, adminRoute.create);
the authenticatedOrNot method is simply :
var authenticatedOrNot = function(req, res, next){
if(req.isAuthenticated()){
next();
}else{
res.redirect("/login");
}
}
Works perfect for logging in to the admin area, and checking if a user is logged in, BUT when I submit a form to the '/admin/new' Post route, the browser hangs. Nothing happens in the console, even with console.log in place :
exports.create = function(req, res){
console.log(req);
// Database logic here
res.redirect('/admin');
}
I cant seem to get it to work. It just hangs, and eventually fails. The browser console just says 'pending' in the network request.
Ive tried removing the 'authenticatedOrNot' method from the post route and same issue, but if I remove all three it works fine.
Im stumped.
Any help guys? Anyone else run into this?
I had a problem very similar to this, so I'm posting this in case it helps out.
The issue seemed to be that i had another function definition inside the passport function, and this was preventing the done handler from being called. I think that was the issue because when I changed the function argument names things started working.
In hindsight I think the error is obvious, but since I'm new to node I'm still a bit uncertain with functions, callbacks, closures, etc, etc. I also have the impression that the node convention is always to use these argument names (err, done, next) and that there is some magic associated with them. I guess not though. Feel free to educate me on this point.
Anyway, I was using a passport local strategy that I copied from a tutorial (at http://scotch.io/tutorials/javascript/easy-node-authentication-setup-and-local).
The tutorial used mongo, but I decided to switch to postgresql. So I used the pg.js module from https://github.com/brianc/node-postgres-pure, and used the sample code provided.
Here's the relevant portion of the code, after I initially copied and pasted the pg.js sample code into the passport tutorial:
//Bad Code
passport.use('local', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
pg.connect(configDB.connectionString, function(err, client, done) {
if (err) {
return console.error('could not connect to postgres', err);
}
client.query('select email, password_hash from admin_user where email = $1', [email], function(err, result) {
// check password against db, and then try to call passports done callback
return done(null, userModel); // this actually invokes the pg.connect done callback
});
});
}));
So when this ran, on the post back to /login, the call to done would invoke pg.connect done, not passport done.
// Good? working code
function(req, email, password, done) {
pg.connect(configDB.connectionString, function(err, client, connect_done) {
if (err) {
return console.error('could not connect to postgres', err);
}
client.query('select email, password_hash from admin_user where email = $1', [email], function(err, result) {
connect_done() // free up postgres connection, which I should have been doing before
// check password against db, and then
return done(null, userModel); // invoke passport's done callback
});
});
}));
This code is now working for me (unless I mis-copied something).
Diagnostic of such a trouble become much more easy when you split more and more and more... Best approach is to use some sniffer (built in Chrome, Firefox, Opera or standalone) and get exactly the headers you sent on to your server. This is very useful since you can localize trouble to frontend app (<form acton="/admin/new" – mistype for example) or backend.
Lets apologize your headers are okay and you send exactly POST at /admin/new route. Since your console.log( req ); does not take effect obviously application does not come to this point. This could be because authenticatedOrNot hangs or because adminRoute.create is not instantiated correctly.
authenticatedOrNot could hang on /login redirection as I see, since you did not provide the way how you handle this route.
adminRoute.create could cause some troubles depending on the way you attached it into your app.
So in resume I need to see more of your code to establish the trouble.

Resources