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());
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);
});
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)
From the multer api doc "You can even stop a file from being uploaded - just return false from the event handler. The file won't be processed or reach the file system."