3

I have a system to upload files with node.js, express and multer, the files are stored inside a static directory. what I want is for them to be stored on the server and be able to see them only if I have logged in.

Issue:

my system to upload is fine, but I need to protect the files in a directory /files/documents/hv.pdf, as the browser saves history whenever I enter the url the file is opened, something that should not happen, how can I avoid access to if the user has not logged in?

I was trying with a Middleware that runs if the url's string bears the name of the / files folder, it's funny that if I do not put the file name or put another name like /files/document/test.txt it works but not When I visited the link in the static folder, I thought it was the cache but it's definitely not that

this Middleware

module.exports = (req,res,next)=>{
    let regex = /^\/files\/.*$/;
    if (!regex.test(req.url)) { return next(); }

    // for test
    req.session.user = {name:"thaylor"}; //comment for not session
    //fin for test

    if(req.session.user){
        next();
    }else{
        res.end('You are not allowed!');
    }
}

Update, this solution 2018-04-2017

Middleware for get root path and protected route app.js

const protectedfile = require("./controllers/protectedfile");

app.use(function(req, res, next) {
    req.rootPath = __dirname;
    next();
});

app.use('/files', protectedfile);
app.use('/files', express.static(path.join(__dirname, 'files')) );

this file controllers/protectedfile.js

const path = require('path'); 
module.exports = (req,res,next)=>{
    if(!req.session.user){
        res.send("Route protected");
    }else{          
        let file = path.join(req.rootPath, req.originalUrl);  
        res.download(file, function (err) {
            if (err) {
                console.log("Error");
                console.log(err);
            } else {
                console.log("success"); 
            }        
        });       
    }
}

thanks to all

  • Of course it won't, a **static** folder is ... well should be static. That is to say you don't want to upload the file into your static folder (typically is named `public`. You can create a folder called `upload` and set `app.set('upload', uloade_path)` and use as `req.app.get('upload')`. – Leo Li Apr 24 '18 at 14:33
  • I do not understand your solution – Thaylor Mosquera Castro Apr 25 '18 at 01:26
  • See my detailed explanation below. Hope that resolve your questions :) – Leo Li Apr 25 '18 at 06:42

2 Answers2

1

Before I'm going to diving into details, one thing to keep in mind is everything in Express.js framework is treated as a piece of middleware. So your oder of code is important (i.e. how your app.use is wired in order). Each time a client access your application would go from the top of your app.js file until something could be returned.

First, a static route means the the content deliver through this given path (folder) is static. Typically, in the top head of app.js file, there is:

app.use(express.static('./public', options));

In the above code, folder 'public' is set to be static. That is anything put into this folder (including the document put into its subfolder) is totally transparent to the public, so that you don't need to specify what have been put into this folder. When a client try to make a HTTP request to your server, Express will scan through the folder and return the document once the requested file could be found; if not, then it go through your next app.use.

And you can assign multiple static routes. For example, if you now attached the following code after the above code:

app.use(express.static('./file', options));

Your server will now scan the folder named after 'file' after nothing was found in './public' path, and try to find out the requested document. Basically, do the same thing as above.

Here is the trick you can play by replacing the above code as this:

app.use('/file', checkIfTheUserHaveLogIn);
app.use('/file', express.static('./file', options));

or in one line:

app.use('/file', checkIfTheUserHaveLogIn, express.static('./file', options));

Here, I use '/file' as the first argument in app.use to specify a special path in the URL that have to be matched. Note, the checkIfTheUserHaveLogIn is a middleware function which serve as controller(function) to decide if allow the client to access the next level of the middleware (by calling next()), which is express.static('./file', options). You can redirect the client to login page or do something else in the checkIfTheUserHaveLogIn if the client have not been granted with that privilege.

In your code, you set a router to screen out the '/file' routing path to perform your authentication. However, because how the order of your middleware matters. It is actually trigger the static router first, and the document can be found, so that the file have been already returned to the requested client. Your middleware is actually never been reached. To avoid it, simply just follow what I was did before, setting another static route and point to a another folder (must not be a subfolder under the first transparent static router, i.e. not under ./public as in my example). Then it should works perfectly.

Hope my explanation clarify your question.

Leo Li
  • 247
  • 4
  • 20
  • 1
    excellent after a while I solved several problems, one of them was to get the root because my file that manages security is in the drivers folder so use this help [link](https://stackoverflow.com/a/31917632/4650557 ) to solve it as the best option. Thank you very much for your help apart your explanation helped me to understand many things and I corrected many things in my code – Thaylor Mosquera Castro Apr 26 '18 at 06:06
  • Nice to heard from your improvement! Since you mentioned security, btw, if you want to set up a global content security policy (CSP), you can write a middleware, and use it at the very top of your `app.js` file, therefore all of your client will be responded with the global CSP rules. You can google it for more information, in case of you don't know what is CSP. – Leo Li Apr 26 '18 at 06:26
  • If the user is authenticated and granted permission to the public folder/subfolders then he would be granted permission to other user's files too. No? – Hairi Jun 27 '21 at 11:10
0
var express = require("express");
var path = require( "path" );
var app = express();

app.use( '/upload', isLoggedIn, express.static( path.join( __dirname, '**your upload folder name**' ) ) );

app.listen( 3000 );

//Use this code if you are using passport.js for authentication mech.
function isLoggedIn(req, res, next) {
    if (req.user) {
        next();
    } else {
        res.redirect('/login');
    }
}

//Use this code for custom sign in implementation
function isLoggedIn(req, res, next) {
    //check if user is logged in
    // your business logic goes here
    if ( condition ) {
        next();
    } else {
        res.redirect('/login');
    }
}

By doing this every time you call localhost:3000/upload/* will via isLoggedIn function.

souravlahoti
  • 716
  • 2
  • 8
  • 29
  • as I send the pdf file to the user, "IF USER IS LOGGED IN LET HIM DOWNLOAD" has no effect when the file is in a static route, it always lets you see it does not matter if it is or not logged in – Thaylor Mosquera Castro Apr 25 '18 at 01:24