the use of Next() in a node.js controller - node.js

I am following the wonderful node-express-mongoose-demo app (link
in the articles.js controller, the .load function has a next() statement and I am confused about it - I thought that next() was only used in routing, passing the flow to the next middleware. why is next() being used here inside a controller? and why are the other controller functions (e.g. .edit ,see code below) NOT using next()..?
/**
* Module dependencies.
*/
var mongoose = require('mongoose')
, Article = mongoose.model('Article')
, utils = require('../../lib/utils')
, extend = require('util')._extend
/**
* Load
*/
exports.load = function(req, res, next, id){
var User = mongoose.model('User')
Article.load(id, function (err, article) {
if (err) return next(err)
if (!article) return next(new Error('not found'))
req.article = article
next()
})
}
....
/**
* Edit an article
*/
exports.edit = function (req, res) {
res.render('articles/edit', {
title: 'Edit ' + req.article.title,
article: req.article
})
}

The .load middleware is calling next() because it is a parameter middleware. These special middlewares allow you to perform logic for specific route parameters. This can be handy if you have a route like /users/:id where you could set up a parameter middleware for id that loads that particular user's profile from the database and then continues on to the actual route handler (which now has the user's profile already available to it). Without this, you may find yourself repeating the same loading logic inside route handlers for different HTTP verbs for the same route path.
The normal route handlers (e.g. edit) don't use next() because they don't need to (unless you encounter a serious HTTP 500-like error and want to call next(err) for example). They typically are the ones that send the response back to the client.

This is because of named parameter in routing.
e.g for route like
app.get('/articles/:id/edit', ArticleController.edit)
we have to tell the routing to resolve "id" by setting app.param('id', ArticleController.load)
This will go on and load the article using the load method then call the next() to pass the control to edit function. "Load" act as middleware which load the article and makes it available in edit method.
Please see express routing for more details.

Related

Node.js REST API - URI Sanitizing?

I would like to require pages in my Node.js server based on the requested URI.
However I concern that this could be a severe security issue since user can inject some malicous chars into the url, something like ../../ and reach to my root server point and reveal all of the code.
So just like throwing a bottle of water to a big fire, I have eliminated the option to send . to the request.
This is not a silverbullet, probably :)
Maybe is there some standard/best practice/guide or keypoints about URI sanitizing in REST API based on Node.js?
Edit - here the code uses the require
// app.js
app.use(require('./services/router')(app));
// router.js middleware
function router(app) {
return function(req, res, next) {
try {
// checking for . in the url
if (req.url.indexOf(".")!=-1) cast.badRequest();
// req.url.split('/')[2] should be customers, users or anything else
require('../../resources/' + req.url.split('/')[2] + '/' + req.url.split('/')[2] + '-router')(app);
next();
} catch(err) { cast.notFound(); }
}
}
module.exports = router;
// rides-router.js (this could be users-router.js or customers-router.js)
module.exports = function(app) {
// GET ride - select a ride
app.get("/v1/rides/:id", dep.verifyToken(), require('./api/v1-get-ride'));
// POST ride - insert a new ride
app.post("/v1/rides", dep.verifyToken(), require('./api/v1-set-ride'));
app.use((req, res, next) => {
cast.notFound();
});
}
You asked how to do it safer. My recommendation is that you put all the resources in an array and run all the app.use() statements with one loop that pulls the resource names from the array at server startup.
I don't like running synchronous require() during a request and I don't like loading code based on user specified characters. Both are avoided with my recommendation.
// add routes for all resources
const resourceList = ['rides', 'products', ...];
for (let r of resourceList) {
app.use(`/${r}`, require(`./resources/${r}/${r}-router`));
}
This seems like less code and 100% safe and no running of synchronous require() during a request.
Advantages:
Fully whitelisted.
No user input involved in selecting code to run.
No synchronous require() during request processing.
All routes installed at server initialization time.
Any errors in route loading (like a missing route file) occur at server startup, not during a user request.

Express.js unique var per request outside routing

In my express application I have a module called helpers thats is required in almost all my routes and modules. This module has a logger method that logs to fluentd (but that's unimportant). While building the data to log I'd like to add a unique identifier of the request, so that all the logs written for the same request have the same unique ID. Using a global var in the app entry point app.use doesn't work because this var would be overwritten every time a new request hits, so the global uuid will change would obviously change in case of high load or long running tasks. The res.locals is not available outside routing, so I can't use it for this matter. Is there a way to create a var that would be unique per request and available in every module or maybe a way to access the res.locals data outside routing? Thank you
EDIT
Maybe an example will help understand better the question.
Suppose I have a module called helpers.js like this:
let helpers = {};
helpers.log = (logData, logName) => {
fluentLogger.emit('', {
name: logName,
//uuid: the needed uuid,
message: logData
});
}
module.exports = helpers;
Now obviously I can do this in my app.js entry point:
app.use(function (req, res, next) {
res.locals.uuid = uuid.v4();
next();
});
and then in every loaded middleware module that requires helpers(adding a new param to the helpers.log method):
const helpers = require('helpers');
router.post('/', (req, res, next) => {
helpers.log('my log message', 'myLogName', res.locals.uuid);
next();
});
and this will normally work. But suppose a big or middle size project where there are hundreds of custom modules and models (not middlewares) and a module may require other modules that require other modules that require finally the helpers module. In this case I should pass the res.locals.uuid as a parameter to every method of every method so that I have it available in the logger method. Not a very good idea. Suppose I have a new module called dbmodel.js that is required in a middleware function:
const helpers = require('helpers');
let dbmodel = {};
dbmodel.getSomeData = (someParam) => {
//some logic
helpers.log('my log message', 'myLogName');
}
module.exports = dbmodel;
The dbmodel has no idea about the res.locals data if I don't pass it from the middleware, so the helpers.log method will also have no idea about this.
In PHP one would normally write a GLOBAL var in the application's entry point so a hypothetical logger function would have access to this global on every method request from whichever class of the application.
Hope this explanation will help :) Thank you
EDIT 2
The solution for this kind of problems is CLS. Thanks to #robertklep for the hint. A good slideshare explaining exactly the same problem (logger with unique ID) and explaining the CLS solutions can be found here: https://www.slideshare.net/isharabash/cls-and-asynclistener
I answered a very similar question here which will solve this problem.
I used to solve the problem the libraries node-uuid and continuation-local-storage. Take a look to the answer of this question and see if it helps:
NodeJS Express - Global Unique Request Id
And you want a bigger explanation, take a look here:
Express.js: Logging info with global unique request ID – Node.js
Yes you can do so by one method .
Every request comes to his routes pass that request inside the middleware.
Suppose you have
app.get('/', function(req, res) {
res.sendFile(path.join(public + "index.html"));
});
a request.
Place Middleware in it .and edit req field coming , in this way you will get the unique variable values for each request
check out this .
https://expressjs.com/en/guide/writing-middleware.html
Like this
var requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
app.use(requestTime)
app.get('/', function (req, res) {
var responseText = 'Hello World!<br>'
responseText += '<small>Requested at: ' + req.requestTime + '</small>'
res.send(responseText)
})
Here req.requestTime is unique for each request.

Unable to register Express middleware

I'm trying to write a very basic piece of middleware for Express that checks to see if a user has some specified role required to access a resource. I have another piece of middleware that comes before this, which adds a user object to the request req for every route requiring authentication (and subsequent authorization).
As such, I define the authorization middleware like this:
_ = require('lodash');
function authorize(req, res, next, roles){
// check to see if user has one of the allowed roles
if(_.contains(roles, req.user.role)){
req.authorized = true;
return next();
}
// otherwise, pass an error
return next(new Error("Unauthorized"));
}
Every user object has a property called role on it, so I use _.contains(roles, req.user.role) to figure out whether or not the allowed roles contain the user's assigned role.
However, when I do this, I get TypeError: Cannot read property 'role' of undefined as soon as I start my Express server. This seems very weird to me, because I have not even made a request, and so of course req.user will be undefined until then.
Is there a way around this?
Example of how I use this middleware:
var app = express();
var router = express.Router();
router.get('/protected/:id', authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']), controllers.protected.retrieve);
When you register the route with
router.get(
'/protected/:id',
authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']),
controllers.protected.retrieve
)
the authorize method gets executed straight away by authorize(...) with the ['ADMINISTRATOR', ...] array being passed as the req param. Hence it is called as soon as you run the code and dies on user object not being present. Even if it didn't die on that, it wouldn't work as intended. You are mixing a middleware and a factory function together.
Express middleware is a function with a (req, res, next) signature, that you don't execute yourself. You need to pass a reference to such a middleware function and Express itself executes it on the request when needed, i.e.:
function authorize(req, res, next) {
...
};
router.get('/protected/:id', authorize, ...);
A parametrized middleware function, as in your case, can be easily created by splitting up to a factory and a middleware function:
// a factory function to create authorization middleware functions for given roles
function authorize(roles) {
// create and return an actual authorization middleware function
// to handle requests using the roles given when created
return function(req, res, next) {
if(_.contains(roles, req.user.role)){
req.authorized = true;
return next();
}
return next(new Error("Unauthorized"));
}
}
router.get(
'/protected/:id',
authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']),
controllers.protected.retrieve
)

Common Pre-Handler for ConnectJS/ExpressJS url handlers?

In my ExpressJS app, several of my urls handlers have the following logic:
See if the user has permission to access a resource
If so, continue
Else, redirect to the main handler.
Is there a way to insert a pre-handler for certain url handlers, via ConnectJS or ExpressJS?
I know I can do it globally, for all handlers, (which I do to insert missing headers as a result from IE's broken XDR).
But, can I do this for a subset of handlers?
I do something like this:
lib/auth.js
exports.checkPerm = function(req, res, next){
//do some permission checks
if ( authorized ) {
next();
} else {
res.render('/401');
return;
}
};
app.js
var auth = require('./lib/auth');
...
app.get('/item/:itemid', auth.checkPerm, routes.item.get);
You can stack middleware before your final route handler like the above line has. It has to have same function signature and call next();
If I understand this question correctly, you know about:
// This is too general
app.use(myAuthMiddleware());
And you are aware that you can add it manually to certain url-handlers:
app.get('/user/profile/edit', myAuthMiddleware(), function(req,res){
/* handle stuff */ });
// but doing this on all your routes is too much work.
What you might not know about express' mounting feature:
// Matches everything under /static/** Cool.
app.use('/static', express.static(__dirname + '/public'));
Or app.all():
// requireAuthentication can call next() and let a more specific
// route handle the non-auth "meat" of the request when it's done.
app.all('/api/*', requireAuthentication);

NodeJS + Express: How to secure a URL

I am using latest versions of NodeJS and ExpressJS (for MVC).
I usually configure my rest paths like this, for example:
app.get('/archive', routes.archive);
Now i want my /admin/* set of URLs to be secured, I mean I need just simple authentication, it's just a draft.
When a user tries to access, for example, /admin/posts, before sending him the corresponding view and data, I check for a req.session.authenticated. If it's not defined, I redirect to the login page.
Login page has a simple validation form, and a sign-in controller method: if user does send "right user" and "right password" I set the session variable and he's authenticated.
What I find difficult, or I don't understand, is how to actually make the "filter" code, I mean, the auth check, before every /admin/* path call.
Does this have something to do with "middleware" express functions?
Thank you
Yep, middleware is exactly what you want. A middleware function is just a function that works just like any other Express route handler, expept it gets run before your actual route handler. You could, for example, do something like this:
function requireLogin(req, res, next) {
if (req.session.loggedIn) {
next(); // allow the next route to run
} else {
// require the user to log in
res.redirect("/login"); // or render a form, etc.
}
}
// Automatically apply the `requireLogin` middleware to all
// routes starting with `/admin`
app.all("/admin/*", requireLogin, function(req, res, next) {
next(); // if the middleware allowed us to get here,
// just move on to the next route handler
});
app.get("/admin/posts", function(req, res) {
// if we got here, the `app.all` call above has already
// ensured that the user is logged in
});
You could specify requireLogin as a middleware to each of the routes you want to be protected, instead of using the app.all call with /admin/*, but doing it the way I show here ensures that you can't accidentally forget to add it to any page that starts with /admin.
A even simpler approach would be to add the following code in the App.js file.
var auth = function(req, res, next) {
if(isAdmin) {
return next();
} else {
return res.status(400)
}
};
app.use('/admin', auth, apiDecrement);
As you can see the middleware is being attached to the route. Before ExpressJS goes forward, it executes the function that you passed as the second parameter.
With this solution you can make different checks before displaying the site to the end user.
Best.
Like brandon, but you can also go the connect route
app.use('/admin', requireLogin)
app.use(app.router)
app.get('/admin/posts', /* middleware */)

Resources