Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to protect a public dynamic folder in nodejs

i show pictures with jade in public/images/picture.jpg but i want to protect some pictures or restrict the access to the public folder how do that??

project
    node_modules
    public
        images
            image.jpg
        javascripts
        stylesheets
        protected_folder*
            image_protected.jpg
    views
like image 366
andrescabana86 Avatar asked Aug 11 '12 00:08

andrescabana86


1 Answers

Note: for all these examples, I'm using an application structured like the following:

.
├── app.js
└── public
    ├── protected
    │   └── file.txt  <-- contains text "protected file"
    └── regular
        └── file.txt  <-- contains text "regular file"

You have a couple of options. The simplest one is to have Express route the request through your router before the public middleware, allowing you to intercept the request:

var express = require('express');
var http = require('http');
var path = require('path');

var app = express();

// use app.router before express.static
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

function userIsAllowed(callback) {
  // this function would contain your logic, presumably asynchronous,
  // about whether or not the user is allowed to see files in the
  // protected directory; here, we'll use a default value of "false"
  callback(false);
};

app.get('/', function(req, res, next) {
  res.end('Home page');
});

app.get('/protected/*', function(req, res, next) {
  userIsAllowed(function(allowed) {
    if (allowed) {
      next(); // call the next handler, which in this case is express.static
    } else {
      res.end('You are not allowed!');
    }
  });
});

http.createServer(app).listen(3000, function(){
  console.log('Express server listening on port 3000');
});

Results:

http://localhost:3000/regular/file.txt # regular file
http://localhost:3000/protected/file.txt # You are not allowed!

The problem with this approach is that the request has to make it all the way through your app's router before a static file can be served, which is not quite as efficient, but may be fine for your needs (you'd need to take some measurements and find out for yourself).


The other option is to insert a small function into the middleware chain that does basically the same thing, but that doesn't require a run through the entire app router:

var express = require('express');
var http = require('http');
var path = require('path');

function userIsAllowed(callback) {
  // this function would contain your logic, presumably asynchronous,
  // about whether or not the user is allowed to see files in the
  // protected directory; here, we'll use a default value of "false"
  callback(false);
};

// This function returns a middleware function
var protectPath = function(regex) {
  return function(req, res, next) {
    if (!regex.test(req.url)) { return next(); }

    userIsAllowed(function(allowed) {
      if (allowed) {
        next(); // send the request to the next handler, which is express.static
      } else {
        res.end('You are not allowed!');
      }
    });
  };
};

var app = express();

app.use(protectPath(/^\/protected\/.*$/));
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res, next) {
  res.end('Home page');
});

http.createServer(app).listen(3000, function(){
  console.log('Express server listening on port 3000');
});

This performs basically the same logic, but instead of routing every request through the entire app router, it runs a small function at the beginning of each request that checks to see if the requested URL matches the regular expression you passed in. If it does, it runs the check to see if the user can access the file.

Results:

http://localhost:3000/regular/file.txt # regular file
http://localhost:3000/protected/file.txt # You are not allowed!
like image 68
Michelle Tilley Avatar answered Oct 16 '22 00:10

Michelle Tilley