2014-05-07 10:29:04 -04:00
|
|
|
Path = require "path"
|
2014-02-12 05:23:40 -05:00
|
|
|
express = require('express')
|
|
|
|
Settings = require('settings-sharelatex')
|
|
|
|
logger = require 'logger-sharelatex'
|
2017-04-03 11:18:30 -04:00
|
|
|
metrics = require('metrics-sharelatex')
|
2014-02-12 05:23:40 -05:00
|
|
|
crawlerLogger = require('./CrawlerLogger')
|
|
|
|
expressLocals = require('./ExpressLocals')
|
|
|
|
Router = require('../router')
|
2017-09-12 05:16:40 -04:00
|
|
|
helmet = require "helmet"
|
2016-11-08 10:32:36 -05:00
|
|
|
UserSessionsRedis = require('../Features/User/UserSessionsRedis')
|
2018-11-15 04:40:33 -05:00
|
|
|
Csrf = require('./Csrf')
|
2016-11-08 10:32:36 -05:00
|
|
|
|
|
|
|
sessionsRedisClient = UserSessionsRedis.client()
|
2014-09-26 12:04:33 -04:00
|
|
|
|
2015-06-30 07:04:41 -04:00
|
|
|
session = require("express-session")
|
|
|
|
RedisStore = require('connect-redis')(session)
|
|
|
|
bodyParser = require('body-parser')
|
|
|
|
methodOverride = require('method-override')
|
|
|
|
cookieParser = require('cookie-parser')
|
2018-10-30 14:18:42 -04:00
|
|
|
bearerToken = require('express-bearer-token')
|
2015-06-30 07:04:41 -04:00
|
|
|
|
2016-11-08 10:32:36 -05:00
|
|
|
# Init the session store
|
|
|
|
sessionStore = new RedisStore(client:sessionsRedisClient)
|
2014-09-26 12:04:33 -04:00
|
|
|
|
2016-09-02 11:17:37 -04:00
|
|
|
passport = require('passport')
|
|
|
|
LocalStrategy = require('passport-local').Strategy
|
|
|
|
|
2015-06-30 07:04:41 -04:00
|
|
|
Mongoose = require("./Mongoose")
|
|
|
|
|
2014-02-12 05:23:40 -05:00
|
|
|
oneDayInMilliseconds = 86400000
|
|
|
|
ReferalConnect = require('../Features/Referal/ReferalConnect')
|
2014-07-01 10:44:12 -04:00
|
|
|
RedirectManager = require("./RedirectManager")
|
2018-06-18 12:37:58 -04:00
|
|
|
ProxyManager = require("./ProxyManager")
|
2014-08-05 06:15:17 -04:00
|
|
|
translations = require("translations-sharelatex").setup(Settings.i18n)
|
2014-09-08 10:40:46 -04:00
|
|
|
Modules = require "./Modules"
|
2014-02-12 05:23:40 -05:00
|
|
|
|
2016-03-18 11:59:03 -04:00
|
|
|
ErrorController = require "../Features/Errors/ErrorController"
|
2016-07-01 06:24:46 -04:00
|
|
|
UserSessionsManager = require "../Features/User/UserSessionsManager"
|
2016-09-02 11:17:37 -04:00
|
|
|
AuthenticationController = require "../Features/Authentication/AuthenticationController"
|
2016-03-18 11:59:03 -04:00
|
|
|
|
2014-02-12 05:23:40 -05:00
|
|
|
|
2015-06-23 08:50:42 -04:00
|
|
|
metrics.event_loop?.monitor(logger)
|
|
|
|
|
2014-02-12 05:23:40 -05:00
|
|
|
if Settings.cacheStaticAssets
|
|
|
|
staticCacheAge = (oneDayInMilliseconds * 365)
|
|
|
|
else
|
|
|
|
staticCacheAge = 0
|
|
|
|
|
|
|
|
app = express()
|
|
|
|
|
2015-06-30 09:38:32 -04:00
|
|
|
webRouter = express.Router()
|
2017-07-05 09:32:55 -04:00
|
|
|
privateApiRouter = express.Router()
|
|
|
|
publicApiRouter = express.Router()
|
2014-07-30 09:22:36 -04:00
|
|
|
|
2015-06-30 07:04:41 -04:00
|
|
|
if Settings.behindProxy
|
|
|
|
app.enable('trust proxy')
|
2015-06-30 09:38:32 -04:00
|
|
|
|
|
|
|
webRouter.use express.static(__dirname + '/../../../public', {maxAge: staticCacheAge })
|
2015-06-30 07:04:41 -04:00
|
|
|
app.set 'views', __dirname + '/../../views'
|
2017-01-20 07:03:02 -05:00
|
|
|
app.set 'view engine', 'pug'
|
2015-06-30 07:04:41 -04:00
|
|
|
Modules.loadViewIncludes app
|
2015-06-30 09:38:32 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2015-07-08 09:34:59 -04:00
|
|
|
app.use bodyParser.urlencoded({ extended: true, limit: "2mb"})
|
2019-03-05 09:44:05 -05:00
|
|
|
# Make sure we can process twice the max doc length, to allow for
|
|
|
|
# - the doc content
|
|
|
|
# - text ranges spanning the whole doc
|
|
|
|
# Also allow some overhead for JSON encoding
|
|
|
|
app.use bodyParser.json({limit: 2 * Settings.max_doc_length + 64 * 1024}) # 64kb overhead
|
2015-06-30 09:38:32 -04:00
|
|
|
app.use methodOverride()
|
2018-10-30 14:18:42 -04:00
|
|
|
app.use bearerToken()
|
2015-06-30 09:38:32 -04:00
|
|
|
|
|
|
|
app.use metrics.http.monitor(logger)
|
2018-09-12 10:25:17 -04:00
|
|
|
RedirectManager.apply(webRouter)
|
2018-07-04 12:59:19 -04:00
|
|
|
ProxyManager.apply(publicApiRouter)
|
2015-06-30 09:38:32 -04:00
|
|
|
|
|
|
|
|
|
|
|
webRouter.use cookieParser(Settings.security.sessionSecret)
|
|
|
|
webRouter.use session
|
2015-06-30 07:04:41 -04:00
|
|
|
resave: false
|
2015-06-30 10:32:01 -04:00
|
|
|
saveUninitialized:false
|
2015-06-30 07:04:41 -04:00
|
|
|
secret:Settings.security.sessionSecret
|
|
|
|
proxy: Settings.behindProxy
|
|
|
|
cookie:
|
|
|
|
domain: Settings.cookieDomain
|
|
|
|
maxAge: Settings.cookieSessionLength
|
|
|
|
secure: Settings.secureCookie
|
|
|
|
store: sessionStore
|
|
|
|
key: Settings.cookieName
|
2016-11-30 04:41:58 -05:00
|
|
|
rolling: true
|
2015-06-30 07:04:41 -04:00
|
|
|
|
2016-09-02 11:17:37 -04:00
|
|
|
# passport
|
|
|
|
webRouter.use passport.initialize()
|
|
|
|
webRouter.use passport.session()
|
|
|
|
|
|
|
|
passport.use(new LocalStrategy(
|
|
|
|
{
|
|
|
|
passReqToCallback: true,
|
|
|
|
usernameField: 'email',
|
|
|
|
passwordField: 'password'
|
|
|
|
},
|
|
|
|
AuthenticationController.doPassportLogin
|
|
|
|
))
|
|
|
|
passport.serializeUser(AuthenticationController.serializeUser)
|
|
|
|
passport.deserializeUser(AuthenticationController.deserializeUser)
|
|
|
|
|
2016-11-01 10:06:54 -04:00
|
|
|
Modules.hooks.fire 'passportSetup', passport, (err) ->
|
|
|
|
if err?
|
|
|
|
logger.err {err}, "error setting up passport in modules"
|
|
|
|
|
2017-07-05 09:32:55 -04:00
|
|
|
Modules.applyNonCsrfRouter(webRouter, privateApiRouter, publicApiRouter)
|
2016-11-11 08:48:29 -05:00
|
|
|
|
2018-11-15 04:40:33 -05:00
|
|
|
webRouter.csrf = new Csrf()
|
|
|
|
webRouter.use webRouter.csrf.middleware
|
2016-11-11 08:48:29 -05:00
|
|
|
webRouter.use translations.expressMiddlewear
|
|
|
|
webRouter.use translations.setLangBasedOnDomainMiddlewear
|
|
|
|
|
2015-06-30 07:04:41 -04:00
|
|
|
# Measure expiry from last request, not last login
|
2015-06-30 09:38:32 -04:00
|
|
|
webRouter.use (req, res, next) ->
|
2015-06-30 07:04:41 -04:00
|
|
|
req.session.touch()
|
2016-09-22 08:48:09 -04:00
|
|
|
if AuthenticationController.isUserLoggedIn(req)
|
|
|
|
UserSessionsManager.touch(AuthenticationController.getSessionUser(req), (err)->)
|
2015-06-30 07:04:41 -04:00
|
|
|
next()
|
2014-02-12 05:23:40 -05:00
|
|
|
|
2015-06-30 09:38:32 -04:00
|
|
|
webRouter.use ReferalConnect.use
|
2017-07-05 09:32:55 -04:00
|
|
|
expressLocals(app, webRouter, privateApiRouter, publicApiRouter)
|
2014-02-12 05:23:40 -05:00
|
|
|
|
2015-06-30 07:04:41 -04:00
|
|
|
if app.get('env') == 'production'
|
2014-02-12 05:23:40 -05:00
|
|
|
logger.info "Production Enviroment"
|
|
|
|
app.enable('view cache')
|
|
|
|
|
|
|
|
app.use (req, res, next)->
|
|
|
|
metrics.inc "http-request"
|
|
|
|
crawlerLogger.log(req)
|
|
|
|
next()
|
|
|
|
|
2019-02-06 09:06:40 -05:00
|
|
|
webRouter.use (req, res, next) ->
|
|
|
|
if Settings.siteIsOpen
|
|
|
|
next()
|
|
|
|
else
|
|
|
|
res.status(503)
|
|
|
|
res.render("general/closed", {title:"maintenance"})
|
|
|
|
|
2016-07-19 12:03:31 -04:00
|
|
|
webRouter.use (req, res, next) ->
|
|
|
|
if Settings.editorIsOpen
|
|
|
|
next()
|
|
|
|
else if req.url.indexOf("/admin") == 0
|
|
|
|
next()
|
|
|
|
else
|
2014-02-12 05:23:40 -05:00
|
|
|
res.status(503)
|
2014-08-01 08:47:14 -04:00
|
|
|
res.render("general/closed", {title:"maintenance"})
|
2014-02-12 05:23:40 -05:00
|
|
|
|
2017-09-12 05:16:40 -04:00
|
|
|
# add security headers using Helmet
|
|
|
|
webRouter.use (req, res, next) ->
|
|
|
|
isLoggedIn = AuthenticationController.isUserLoggedIn(req)
|
|
|
|
isProjectPage = !!req.path.match('^/project/[a-f0-9]{24}$')
|
|
|
|
|
|
|
|
helmet({ # note that more headers are added by default
|
|
|
|
dnsPrefetchControl: false
|
|
|
|
referrerPolicy: { policy: 'origin-when-cross-origin' }
|
|
|
|
noCache: isLoggedIn || isProjectPage
|
2017-09-13 05:53:11 -04:00
|
|
|
noSniff: false
|
|
|
|
hsts: false
|
|
|
|
frameguard: false
|
2017-09-12 05:16:40 -04:00
|
|
|
})(req, res, next)
|
|
|
|
|
2019-05-07 06:47:41 -04:00
|
|
|
profiler = require "v8-profiler-node8"
|
2017-07-05 09:32:55 -04:00
|
|
|
privateApiRouter.get "/profile", (req, res) ->
|
2015-02-03 06:05:23 -05:00
|
|
|
time = parseInt(req.query.time || "1000")
|
|
|
|
profiler.startProfiling("test")
|
|
|
|
setTimeout () ->
|
|
|
|
profile = profiler.stopProfiling("test")
|
|
|
|
res.json(profile)
|
|
|
|
, time
|
2014-02-12 05:23:40 -05:00
|
|
|
|
2019-03-28 11:00:22 -04:00
|
|
|
privateApiRouter.get "/heapdump", (req, res)->
|
2016-04-19 11:48:51 -04:00
|
|
|
require('heapdump').writeSnapshot '/tmp/' + Date.now() + '.web.heapsnapshot', (err, filename)->
|
2015-11-30 11:16:16 -05:00
|
|
|
res.send filename
|
|
|
|
|
2014-02-12 05:23:40 -05:00
|
|
|
logger.info ("creating HTTP server").yellow
|
|
|
|
server = require('http').createServer(app)
|
|
|
|
|
2017-06-06 06:31:29 -04:00
|
|
|
# provide settings for separate web and api processes
|
|
|
|
# if enableApiRouter and enableWebRouter are not defined they default
|
|
|
|
# to true.
|
|
|
|
notDefined = (x) -> !x?
|
|
|
|
enableApiRouter = Settings.web?.enableApiRouter
|
|
|
|
if enableApiRouter or notDefined(enableApiRouter)
|
|
|
|
logger.info("providing api router");
|
2017-07-05 09:32:55 -04:00
|
|
|
app.use(privateApiRouter)
|
2017-06-06 06:31:29 -04:00
|
|
|
app.use(ErrorController.handleApiError)
|
|
|
|
|
|
|
|
enableWebRouter = Settings.web?.enableWebRouter
|
|
|
|
if enableWebRouter or notDefined(enableWebRouter)
|
|
|
|
logger.info("providing web router");
|
2017-07-05 09:32:55 -04:00
|
|
|
app.use(publicApiRouter) # public API goes with web router for public access
|
2017-07-05 10:06:23 -04:00
|
|
|
app.use(ErrorController.handleApiError)
|
2017-06-06 06:31:29 -04:00
|
|
|
app.use(webRouter)
|
|
|
|
app.use(ErrorController.handleError)
|
2015-06-30 09:38:32 -04:00
|
|
|
|
2019-02-19 09:51:34 -05:00
|
|
|
metrics.injectMetricsRoute(webRouter)
|
|
|
|
|
2017-07-05 09:32:55 -04:00
|
|
|
router = new Router(webRouter, privateApiRouter, publicApiRouter)
|
2014-02-12 05:23:40 -05:00
|
|
|
|
|
|
|
module.exports =
|
|
|
|
app: app
|
|
|
|
server: server
|