provide a static server which forbids symlinks
prevents mismatch between rootdir of server and rootdir of symlink checking middleware
This commit is contained in:
27
app.coffee
27
app.coffee
@@ -37,24 +37,12 @@ app.delete "/project/:project_id", CompileController.clearCache
|
|||||||
app.get "/project/:project_id/sync/code", CompileController.syncFromCode
|
app.get "/project/:project_id/sync/code", CompileController.syncFromCode
|
||||||
app.get "/project/:project_id/sync/pdf", CompileController.syncFromPdf
|
app.get "/project/:project_id/sync/pdf", CompileController.syncFromPdf
|
||||||
|
|
||||||
url = require "url"
|
ForbidSymlinks = require "./app/js/StaticServerForbidSymlinks"
|
||||||
|
|
||||||
staticForbidSymLinks = (root, options) ->
|
# create a static server which does not allow access to any symlinks
|
||||||
expressStatic = express.static root, options
|
# avoids possible mismatch of root directory between middleware check
|
||||||
basePath = Path.resolve(root)
|
# and serving the files
|
||||||
return (req, res, next) ->
|
staticServer = ForbidSymlinks express.static, Settings.path.compilesDir, setHeaders: (res, path, stat) ->
|
||||||
path = url.parse(req.url).pathname
|
|
||||||
requestedFsPath = Path.normalize("#{basePath}/#{path}")
|
|
||||||
fs.realpath requestedFsPath, (err, realFsPath)->
|
|
||||||
if err?
|
|
||||||
return res.send(500)
|
|
||||||
else if requestedFsPath != realFsPath
|
|
||||||
logger.warn requestedFsPath:requestedFsPath, realFsPath:realFsPath, path: req.params[0], project_id: req.params.project_id, "trying to access a different file (symlink), aborting"
|
|
||||||
return res.send(404)
|
|
||||||
else
|
|
||||||
expressStatic(req, res, next)
|
|
||||||
|
|
||||||
staticServer = staticForbidSymLinks Settings.path.compilesDir, setHeaders: (res, path, stat) ->
|
|
||||||
if Path.basename(path) == "output.pdf"
|
if Path.basename(path) == "output.pdf"
|
||||||
res.set("Content-Type", "application/pdf")
|
res.set("Content-Type", "application/pdf")
|
||||||
# Calculate an etag in the same way as nginx
|
# Calculate an etag in the same way as nginx
|
||||||
@@ -68,9 +56,10 @@ staticServer = staticForbidSymLinks Settings.path.compilesDir, setHeaders: (res,
|
|||||||
# that could be used in same-origin/XSS attacks.
|
# that could be used in same-origin/XSS attacks.
|
||||||
res.set("Content-Type", "text/plain")
|
res.set("Content-Type", "text/plain")
|
||||||
|
|
||||||
app.get "/project/:project_id/output/*", require("./app/js/SymlinkCheckerMiddlewear"), (req, res, next) ->
|
app.get "/project/:project_id/output/*", (req, res, next) ->
|
||||||
if req.query?.build? && req.query.build.match(OutputCacheManager.BUILD_REGEX)
|
if req.query?.build? && req.query.build.match(OutputCacheManager.BUILD_REGEX)
|
||||||
req.url = "/#{req.params.project_id}/" + OutputCacheManager.path(req.query.build) + "/#{req.params[0]}"
|
# for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId)
|
||||||
|
req.url = "/#{req.params.project_id}/" + OutputCacheManager.path(req.query.build, "/#{req.params[0]}")
|
||||||
else
|
else
|
||||||
req.url = "/#{req.params.project_id}/#{req.params[0]}"
|
req.url = "/#{req.params.project_id}/#{req.params[0]}"
|
||||||
staticServer(req, res, next)
|
staticServer(req, res, next)
|
||||||
|
|||||||
@@ -13,9 +13,13 @@ module.exports = OutputCacheManager =
|
|||||||
CACHE_LIMIT: 32 # maximum of 32 cache directories
|
CACHE_LIMIT: 32 # maximum of 32 cache directories
|
||||||
CACHE_AGE: 60*60*1000 # up to one hour old
|
CACHE_AGE: 60*60*1000 # up to one hour old
|
||||||
|
|
||||||
path: (buildId) ->
|
path: (buildId, file) ->
|
||||||
# used by static server, given build id return '.cache/clsi/buildId'
|
# used by static server, given build id return '.cache/clsi/buildId'
|
||||||
return Path.join(OutputCacheManager.CACHE_SUBDIR, buildId)
|
if buildId.match OutputCacheManager.BUILD_REGEX
|
||||||
|
return Path.join(OutputCacheManager.CACHE_SUBDIR, buildId, file)
|
||||||
|
else
|
||||||
|
# for invalid build id, return top level
|
||||||
|
return file
|
||||||
|
|
||||||
saveOutputFiles: (outputFiles, compileDir, callback = (error) ->) ->
|
saveOutputFiles: (outputFiles, compileDir, callback = (error) ->) ->
|
||||||
# make a compileDir/CACHE_SUBDIR/build_id directory and
|
# make a compileDir/CACHE_SUBDIR/build_id directory and
|
||||||
|
|||||||
24
app/coffee/StaticServerForbidSymlinks.coffee
Normal file
24
app/coffee/StaticServerForbidSymlinks.coffee
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Path = require("path")
|
||||||
|
fs = require("fs")
|
||||||
|
Settings = require("settings-sharelatex")
|
||||||
|
logger = require("logger-sharelatex")
|
||||||
|
url = require "url"
|
||||||
|
|
||||||
|
module.exports = ForbidSymlinks = (staticFn, root, options) ->
|
||||||
|
expressStatic = staticFn root, options
|
||||||
|
basePath = Path.resolve(root)
|
||||||
|
return (req, res, next) ->
|
||||||
|
path = url.parse(req.url)?.pathname
|
||||||
|
requestedFsPath = Path.normalize("#{basePath}/#{path}")
|
||||||
|
fs.realpath requestedFsPath, (err, realFsPath)->
|
||||||
|
if err?
|
||||||
|
logger.warn err:err, requestedFsPath:requestedFsPath, realFsPath:realFsPath, path: req.params[0], project_id: req.params.project_id, "error checking file access"
|
||||||
|
if err.code == 'ENOENT'
|
||||||
|
return res.sendStatus(404)
|
||||||
|
else
|
||||||
|
return res.sendStatus(500)
|
||||||
|
else if requestedFsPath != realFsPath
|
||||||
|
logger.warn requestedFsPath:requestedFsPath, realFsPath:realFsPath, path: req.params[0], project_id: req.params.project_id, "trying to access a different file (symlink), aborting"
|
||||||
|
return res.sendStatus(404)
|
||||||
|
else
|
||||||
|
expressStatic(req, res, next)
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
Path = require("path")
|
|
||||||
fs = require("fs")
|
|
||||||
Settings = require("settings-sharelatex")
|
|
||||||
logger = require("logger-sharelatex")
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (req, res, next)->
|
|
||||||
basePath = Path.resolve("#{Settings.path.compilesDir}/#{req.params.project_id}")
|
|
||||||
requestedFsPath = Path.normalize("#{basePath}/#{req.params[0]}")
|
|
||||||
fs.realpath requestedFsPath, (err, realFsPath)->
|
|
||||||
if err?
|
|
||||||
return res.send(500)
|
|
||||||
else if requestedFsPath != realFsPath
|
|
||||||
logger.warn requestedFsPath:requestedFsPath, realFsPath:realFsPath, path: req.params[0], project_id: req.params.project_id, "trying to access a different file (symlink), aborting"
|
|
||||||
return res.send(404)
|
|
||||||
else
|
|
||||||
return next()
|
|
||||||
Reference in New Issue
Block a user