Flaudre Flaudre - 12 days ago 6
Node.js Question

How to serve user specific static content in Express.js

I want to serve user-specific static content in Express. That means, if a user is logged in, his private static folder is served by express. Other users shall not have access.

I tried the following (see below), but the static content is not being served. In fact, the route seems to be completely ignored and I get a 404.

I am not sure if the way I do it is the right way to go and if express is capable of dynamically serving different static folders. Thanks in advance for your thoughts on this.

Here's the code (simplified):

routes.js:

express = require 'express'
router = express.Router()

router.use '/user/assets', (req, res, next) ->
if req.user
userpath = 'uploads/' + md5(req.user._id)
if not fs.existsSync userpath
fs.mkdirSync userpath
console.log "Created user directory at " + userpath

express.static(userpath)
next()

module.exports = router


index.js:

express = require 'express'
app = express()
app.use '/', require './routes'


Sidenotes:

The md5 is just a way of escaping weird characters in the user id, which is a string. I know there is a possibility for a mismatch, which is tiny, and about which I don't wanna care for now. Concerns about general security of the fashion of the solving attempt are appreciated.
The code is written in CoffeeScript.

req.user
contains a valid user element.

Answer

Just calling express.static is not enough, you need to use() it with the router. Unfortunately you can't directly do that, since you require a different set of routes for each user.

Calling express.static will return a middleware function. You could call it directly, i.e. something like this:

var files = express.static(userpath);
return files(req, res, next);

However that's still not enough, as the middleware uses req.url to build the file path. The express router adjusts this property and removes the mount point (see req.originalUrl in the docs). So you need to strip /user/assets from it, before calling the middleware.

By the way, you should set the DEBUG environment variable for node. It allows you to see what routes are created by express, which is very handy in debugging express.static 404 problems. E.g. you'd do $ DEBUG=* node index.js on Linux.

As you can see the approach starts to be a bit hacky and creating a new express.static middleware on each request is not very performance friendly too. So depending on what your user directories contain, using res.sendFile might actually be better.

As a sidenote, I assume you've checked that req.user actually contains something if the user is logged in.