Server.coffee 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. Path = require "path"
  2. express = require('express')
  3. Settings = require('settings-sharelatex')
  4. logger = require 'logger-sharelatex'
  5. metrics = require('metrics-sharelatex')
  6. crawlerLogger = require('./CrawlerLogger')
  7. expressLocals = require('./ExpressLocals')
  8. Router = require('../router')
  9. helmet = require "helmet"
  10. UserSessionsRedis = require('../Features/User/UserSessionsRedis')
  11. Csrf = require('./Csrf')
  12. sessionsRedisClient = UserSessionsRedis.client()
  13. session = require("express-session")
  14. RedisStore = require('connect-redis')(session)
  15. bodyParser = require('body-parser')
  16. methodOverride = require('method-override')
  17. cookieParser = require('cookie-parser')
  18. bearerToken = require('express-bearer-token')
  19. # Init the session store
  20. sessionStore = new RedisStore(client:sessionsRedisClient)
  21. passport = require('passport')
  22. LocalStrategy = require('passport-local').Strategy
  23. Mongoose = require("./Mongoose")
  24. oneDayInMilliseconds = 86400000
  25. ReferalConnect = require('../Features/Referal/ReferalConnect')
  26. RedirectManager = require("./RedirectManager")
  27. ProxyManager = require("./ProxyManager")
  28. translations = require("translations-sharelatex").setup(Settings.i18n)
  29. Modules = require "./Modules"
  30. ErrorController = require "../Features/Errors/ErrorController"
  31. UserSessionsManager = require "../Features/User/UserSessionsManager"
  32. AuthenticationController = require "../Features/Authentication/AuthenticationController"
  33. metrics.event_loop?.monitor(logger)
  34. if Settings.cacheStaticAssets
  35. staticCacheAge = (oneDayInMilliseconds * 365)
  36. else
  37. staticCacheAge = 0
  38. app = express()
  39. webRouter = express.Router()
  40. privateApiRouter = express.Router()
  41. publicApiRouter = express.Router()
  42. if Settings.behindProxy
  43. app.enable('trust proxy')
  44. webRouter.use express.static(__dirname + '/../../../public', {maxAge: staticCacheAge })
  45. app.set 'views', __dirname + '/../../views'
  46. app.set 'view engine', 'pug'
  47. Modules.loadViewIncludes app
  48. app.use bodyParser.urlencoded({ extended: true, limit: "2mb"})
  49. # Make sure we can process twice the max doc length, to allow for
  50. # - the doc content
  51. # - text ranges spanning the whole doc
  52. # Also allow some overhead for JSON encoding
  53. app.use bodyParser.json({limit: 2 * Settings.max_doc_length + 64 * 1024}) # 64kb overhead
  54. app.use methodOverride()
  55. app.use bearerToken()
  56. app.use metrics.http.monitor(logger)
  57. RedirectManager.apply(webRouter)
  58. ProxyManager.apply(publicApiRouter)
  59. webRouter.use cookieParser(Settings.security.sessionSecret)
  60. webRouter.use session
  61. resave: false
  62. saveUninitialized:false
  63. secret:Settings.security.sessionSecret
  64. proxy: Settings.behindProxy
  65. cookie:
  66. domain: Settings.cookieDomain
  67. maxAge: Settings.cookieSessionLength
  68. secure: Settings.secureCookie
  69. store: sessionStore
  70. key: Settings.cookieName
  71. rolling: true
  72. # passport
  73. webRouter.use passport.initialize()
  74. webRouter.use passport.session()
  75. passport.use(new LocalStrategy(
  76. {
  77. passReqToCallback: true,
  78. usernameField: 'email',
  79. passwordField: 'password'
  80. },
  81. AuthenticationController.doPassportLogin
  82. ))
  83. passport.serializeUser(AuthenticationController.serializeUser)
  84. passport.deserializeUser(AuthenticationController.deserializeUser)
  85. Modules.hooks.fire 'passportSetup', passport, (err) ->
  86. if err?
  87. logger.err {err}, "error setting up passport in modules"
  88. Modules.applyNonCsrfRouter(webRouter, privateApiRouter, publicApiRouter)
  89. webRouter.csrf = new Csrf()
  90. webRouter.use webRouter.csrf.middleware
  91. webRouter.use translations.expressMiddlewear
  92. webRouter.use translations.setLangBasedOnDomainMiddlewear
  93. # Measure expiry from last request, not last login
  94. webRouter.use (req, res, next) ->
  95. req.session.touch()
  96. if AuthenticationController.isUserLoggedIn(req)
  97. UserSessionsManager.touch(AuthenticationController.getSessionUser(req), (err)->)
  98. next()
  99. webRouter.use ReferalConnect.use
  100. expressLocals(app, webRouter, privateApiRouter, publicApiRouter)
  101. if app.get('env') == 'production'
  102. logger.info "Production Enviroment"
  103. app.enable('view cache')
  104. app.use (req, res, next)->
  105. metrics.inc "http-request"
  106. crawlerLogger.log(req)
  107. next()
  108. webRouter.use (req, res, next) ->
  109. if Settings.siteIsOpen
  110. next()
  111. else
  112. res.status(503)
  113. res.render("general/closed", {title:"maintenance"})
  114. webRouter.use (req, res, next) ->
  115. if Settings.editorIsOpen
  116. next()
  117. else if req.url.indexOf("/admin") == 0
  118. next()
  119. else
  120. res.status(503)
  121. res.render("general/closed", {title:"maintenance"})
  122. # add security headers using Helmet
  123. webRouter.use (req, res, next) ->
  124. isLoggedIn = AuthenticationController.isUserLoggedIn(req)
  125. isProjectPage = !!req.path.match('^/project/[a-f0-9]{24}$')
  126. helmet({ # note that more headers are added by default
  127. dnsPrefetchControl: false
  128. referrerPolicy: { policy: 'origin-when-cross-origin' }
  129. noCache: isLoggedIn || isProjectPage
  130. noSniff: false
  131. hsts: false
  132. frameguard: false
  133. })(req, res, next)
  134. profiler = require "v8-profiler"
  135. privateApiRouter.get "/profile", (req, res) ->
  136. time = parseInt(req.query.time || "1000")
  137. profiler.startProfiling("test")
  138. setTimeout () ->
  139. profile = profiler.stopProfiling("test")
  140. res.json(profile)
  141. , time
  142. privateApiRouter.get "/heapdump", (req, res)->
  143. require('heapdump').writeSnapshot '/tmp/' + Date.now() + '.web.heapsnapshot', (err, filename)->
  144. res.send filename
  145. logger.info ("creating HTTP server").yellow
  146. server = require('http').createServer(app)
  147. # provide settings for separate web and api processes
  148. # if enableApiRouter and enableWebRouter are not defined they default
  149. # to true.
  150. notDefined = (x) -> !x?
  151. enableApiRouter = Settings.web?.enableApiRouter
  152. if enableApiRouter or notDefined(enableApiRouter)
  153. logger.info("providing api router");
  154. app.use(privateApiRouter)
  155. app.use(ErrorController.handleApiError)
  156. enableWebRouter = Settings.web?.enableWebRouter
  157. if enableWebRouter or notDefined(enableWebRouter)
  158. logger.info("providing web router");
  159. app.use(publicApiRouter) # public API goes with web router for public access
  160. app.use(ErrorController.handleApiError)
  161. app.use(webRouter)
  162. app.use(ErrorController.handleError)
  163. metrics.injectMetricsRoute(webRouter)
  164. router = new Router(webRouter, privateApiRouter, publicApiRouter)
  165. module.exports =
  166. app: app
  167. server: server