Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs Express 4 Multer | Stop file upload if user not authorized

I'm using multer as multipart middelware for express4.

Express is configured to use passport as auth middelware, but I cannot find a way to prevent file upload if the user is not authenticated.

I thought to use onFileUploadStart to reject the file, but I cannot find a link with "request" object, with which it would be possible to match the user.

Below code use in configuring express vs multer:

...
// Multipart file upload
app.use(multer(
{
  dest: wwwroot + path.sep + 'uploaded' + path.sep, 
  onFileUploadStart: function (file) {
    //TODO : apply security check : user auth, file size, number...
    console.log(file.fieldname + ' is starting ...')
},
onFileUploadComplete: function (file) {
    console.log(file.fieldname + ' uploaded to  ' + file.path)
}
}));
...
app.use(passport.auth.initialize());
app.use(passport.auth.session());   
like image 778
LorenzoGi Avatar asked Aug 23 '14 10:08

LorenzoGi


2 Answers

EDIT

I'll leave the answer below in case it helps, but the answer is actually quite simple: you need to move the two calls to app.use(passport) above the call to app.use(multer). Each step in the express chain is processed in order, so if you wish reject a bad auth attempt, do it before you handle the incoming file upload.


There is probably a better way to do this, but this should get you started. Change your express config to use a closure and you'll have full access to the req variable.

app.use(function(req, res, next) {
  var handler = multer({
    dest: wwwroot + path.sep + 'uploaded' + path.sep, 
    onFileUploadStart: function (file) {
      // You now have access to req
      console.dir(req);
      console.log(file.fieldname + ' is starting ...')
    },
    onFileUploadComplete: function (file) {
      console.log(file.fieldname + ' uploaded to  ' + file.path)
    }
  });
  handler(req, res, next);
});
like image 115
morloch Avatar answered Nov 19 '22 23:11

morloch


Okay I think I got a solution for you. It is not a complete solution for my own problems, but it serves for your specific case, which is checking if a user is authorized through Passport before downloading the file.

The trick is to use middlewares in your post handlers to do one thing at a time. First passport will be called to put user object in the req object. Then, you check if user is authenticated. If it is the case, you download the file and then use it. Here's a sample:

//don't add multer as a middleware to all requests. 
//If you do this, people will be able to upload files
//in ALL YOUR 'post' handlers!!! 
var Multer = require('multer');

//this is a middleware to check if user is authenticated
function check(req, res, next){
    if(req.isAuthenticated()){
        console.log(req.user);
        next();
    }
    else{
        res.send(401);
    }
}

//this is a middleware to be called after file is downloaded
function finish(req, res, next){
    var filePath = req.files.file.path;
    res.send("Hello " + req.user.name + "! Your file was uploaded to " + filePath);
}

//this is the route handler. First check auth. If so, 
//proceed to multer middleware to download file
//lastly, use the file as you need
app.post('/test', [check, Multer(), finish]);

This only works because Passport does not use body data to authenticate the user: it uses sessions that are not in the body. So you can use Passport and get user data, but you can't, for instance, be sure you have all non-file fields parsed before start downloading the file (since they come all together in express req stream)

like image 33
Marcel Batista Avatar answered Nov 19 '22 23:11

Marcel Batista