A few questions about express validation - node.js

I have a few questions about input validation with node, maybe there's a few concepts I'm just misunderstanding and need clarification. I'm currently using express-validator.
I currently have something like:
function validate(req) {
req.assert('name', 'Please enter a name').notEmpty()
req.assert('email', 'Please enter an email').notEmpty()
var errors = req.validationErrors();
return errors;
};
app.post('/contactform', function(req, res){
var err = validate(req);
if (!err) {
res.send('everything is good to go')
} else {
res.send(err)
}
});
I understand the validation part, however how do I go about actually using the information once I sanitize it?
I've tried stuff along the lines of
var email = req.sanitize('email').toString()
But this just gives me an [object object].
So I have a few questions:
How do I actually go about using sanitized strings? or does the express-validator module just validate/sanitize and I need to do something else to actually be able to use the sanitized output?
Also, should input be sanitized before being validated for security?
EDIT:
So I looked at the source code for express-validator and I found that the parameters are stored as req.param('name') or req.param('email'). I'm assuming that if you sanitize and/or validate the parameters and then access them, you receive the sanitized version. This answers my first question, still curious about the second question regarding general security.

I use trim() chained to sanitize():
var str = req.sanitize('input').trim();

Related

Passing REST URL parameter as query condition in Mongoose

Newbie in nodejs/mongoDB here. I've tried, with no success,
to find the answer to my problem before posting here.
I'm creating a simple node RESTAPI get services with Mongoose. I'm trying to pass the field value of the collection to retrieve a specific document.
Like this http://localhost:3000/infrakpi/fieldvalue in the browser
I've written this following piece of code.
app.get('/infrakpi/:system',(req, res) => {
Infrakpi.getInfrakpiBySystem(req.params.system, function(err, infrakpibysystem){
if (err) {
throw err;
}
res.json(infrakpibysystem);
});
});
I have defined the get method in my mongoose model like below.
//Get Infrakpi by System
module.exports.getInfrakpiBySystem = function (system, callback) {
Infrakpi.find({system: 'system'}, callback)
}
when system is passed as fieldvalue in the restURL, I want to retrieve the specific document in the collection.
I understand that this may be very basic question but I get result when I use findById for _id field. But client will call only with the specific field.
Appreciate your help.
Not Sure if i can call it stackoverflow luck. I overlooked the quotes in get method in the model. Once I removed them, it worked.
//Get Infrakpi by System
module.exports.getInfrakpiBySystem = function (system, callback) {
Infrakpi.find({system: system}, callback)
}
I'm leaving the question here without deleting, if it can help someone else in the future.

Very simple Node.js POST form inquiries

I have a simple node.js app using express static and nodemailer with a POST form that emails the filled fields to myself. My problems are very simple, I'm just quite new to Node so I can't find a way to do them.
My first problem is that I can't find a way to put all the form data into the email's text. Below, I am trying to store my form data in a JSON and call it in the email text, but it doesn't work. It has only correctly worked for me when I only used one variable (ex. just req.body.name) for the text. How can I format my data together in the email?
My second problem is that I can find a way to handle the app after the email is sent. I want it to redirect to a success page, as shown in the marked line, but it does not work. Instead, the page goes to /reqform and displays an error message saying success.html doesn't exist (it is in the same public folder as my html file). I believe the problem lies in my sendFile usage, but I'm not sure.
app.post('/reqform', urlencodedParser, function (req, res) {
response = {
name: req.body.name,
email: req.body.email,
phone: req.body.phone
};
var mailContent = {
from: 'myemail#gmail.com',
to: 'myemail#gmail.com',
subject: 'Service Request From req.body.name',
text: response //*** Problem #1
};
transporter.sendMail(mailClient, function (error, info) {
if (error) {
console.log(error);
} else {
res.sendFile("success.html"); //** Problem #2
}
});
})
Any help is greatly appreciated. Thanks!
The default string value for a JavaScript Object is just "[object Object]". If you want anything else, you'll have to be specific with how you want it represented.
For example, JSON is a text/string format that represents values like Objects. It's separate from the Object itself, so you'll need to convert to use it:
var mailContent = {
// ...
text: JSON.stringify(response)
}
Or, provide your own formatting:
var mailContent = {
// ...
text: `Name: ${response.name}\nEmail: ${response.email}\nPhone: ${response.phone}`
}
It might be better to use res.redirect() in this case, allowing the client/browser to request success.html via your application's static() middleware:
res.redirect('/success.html');
res.sendFile() doesn't collaborate with any static() middleware to know about your public folder. It expects you to provide a full path either directly or with its root option:
res.sendFile(path.join(__dirname, 'public/success.html'));

Express-validator .getValidationResult()

I'm working on a simple login for a web application, and can't seem handle .getValidationResult() correctly. I've spent quite a bit of time pouring over the npm documentation for express-validator, trying to find an answer in tutorials, and looking on sites like Stack Overflow without managing to find the answer to my question. Perhaps I just don't know the right question to ask.
I want to ensure that
the user submitted something that has the form of an email address,
that the password isn't empty. I then want to
sanitize the email before interacting with the DB later on, then
check to see if any of the first 3 procedures failed. If there were failures, return the user to the login page.
My question is what is the correct way to use express-validator's .getValidationResult()?
Here's the offending piece of code:
export let postLogin = (req: Request, res: Response, next: NextFunction) => {
req.assert("email", "Email is not valid").isEmail();
req.assert("password", "Password cannot be blank").notEmpty();
req.sanitize("email").normalizeEmail({ gmail_remove_dots: false });
req.getValidationResult().then(function(result){
if (result != undefined) {
console.log(result.array();
return res.redirect("/login");
}
});
//do other login related stuff
}
I'm guessing that something simple is causing my error here, but I can't seem to find what it is.
It returns a promise for an object called Validation Object. This object contains information about the errors that your application has had.
The explanation.
Runs all validations and returns a validation result object for the
errors gathered, for both sync and async validators.
All it does is returning errors if there is one. Here is some example code returned by that function.
//The error object
{
"msg": "The error message",
"param": "param.name.with.index[0]",
"value": "param value",
// Location of the param that generated this error.
// It's either body, query, params, cookies or headers.
"location": "body",
// nestedErrors only exist when using the oneOf function
"nestedErrors": [{ ... }]
}
The function returns isEmpty() when there is no errors to display.
The function returns .array([options]) if there are any errors. Errors are located in [options] array.
Check out this link for the example code of what it might return.
UPDATE
You can also just use it like this, which is easier.
Please note that this is new API as of v4.0.0 release of express-validator.
const { check, validationResult } = require('express-validator/check');
//go to a link
app.get('/myURL', (req, res, next) => {
// Get the validation result\
const errors = validationResult(req).throw();
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors }); //err.mapped()
});

Node/Express/Jade passing username back to view

This is my first project with all these technologies, I typically do Angular, but I am working for a charity ( and keen to learn node ). This is day three.
During a login, this is the method called:
schema.statics.authenticateAndLoad = function(req, res, next) {
var userId = req.body.email;
res.locals.userId = userId;
This is supposed to store the value so it doesn't need to be reentered. If login fails, it does this:
return next('Login failed. Please enter your details and try again.');
Then in my Jade template:
if(locals.userId)
p Welcome to #{userId}
else
p Welcome
The actual template has code to try to do what I want:
input(type='text', name='email', id="inputEmail", placeholder="Email", value="#{body.email || ''}")
But this does not work.
So, I THINK this means my setting a value in the result is lost when I call 'next', but, because it's also passing in this error object to show on the screen, I'm not sure how I would go about making sure this error shows AND make the value pass through . Right now, my text just says 'welcome' and never 'welcome to xx', this is test code, I'm just proving the value is not being passed through.
My question is, what's the correct way to pass the value through to my template, and ALSO trigger the error message that is being shown.
The code, when I step in to it, goes deep in to Express and checks for errors there.
Hi it is good to see some developers doing charity work.
Typically what you would use is something like this assuming this is a piece of middleware
schema.statics.authenticateAndLoad = function(req, res, next) {
var userId = req.body.email;
res.locals.userId = userId;
loginFunction(userdetails,function(error,result){
//if there is an error you need to render the page or do a redirect to the
//login page
if(error){
var msg = 'Login failed. Please enter your details and try again.'
return res.render('login',{userId: userId,error: msg})
//this renders the login page and passes req.body.email to the page as userID and the msg as error
}
if(result){
//if this is correct you return next() as you are saying
//you may go through
return next()
}
}
}
then on your jade to display the error you use and userID
p #{userID}
p #{error}
So to answer your question the correct way to send the value to jade you pass it in using this and pass the error in as a variable.
return res.render(template_name,{userId: req.body.email,error: msg})
I hope this helps you out

Tidy callbacks node.js

Trying to think of a logical way of structuring this. For simplicity, I am creating a user registration page utilising Node.js, Redis and Express.js.
User posts details to page.
Username is confirmed to be valid then Redis checks username is unique. If it is, we continue, if it isn't we return an error message and all the previous details.
Password is confirmed to be valid. If it isn't an error is returned and we don't continue.
Email is confirmed to be unique with Redis. If it is we continue, if it isn't we return an error message and stop.
If no errors at this point, the data is inserted into Redis.
This seems very simple, but using callbacks has generated a total mess - particularly when it comings to returning an error.
How can I structure this in a tidy way?
What you've experienced is callback hell. There are a variety of things you could do like name your callback functions instead of inlining them, follow the same pattern etc...
However, I would recommend you have a look at the async module.
In your, very typical, case I would use async.series like this:
var validateUserName = function(username, callback){
if(username!='valid'){
return callback('invalid username');
}
};
var checkRedis = function(username, callback){
// check to redis
};
var checkPassword = function(password, callback){
// if password valid callback();
// else callback('invalid password');
}
etc...
async.series([checkUserName, checkRedis, checkPassword, etc...], next);

Resources