overleaf/services/web/app/coffee/infrastructure/ExpressLocals.coffee

379 lines
12 KiB
CoffeeScript
Raw Normal View History

2014-02-12 05:23:40 -05:00
logger = require 'logger-sharelatex'
fs = require 'fs'
crypto = require 'crypto'
Settings = require('settings-sharelatex')
SubscriptionFormatters = require('../Features/Subscription/SubscriptionFormatters')
querystring = require('querystring')
2014-07-24 08:24:08 -04:00
SystemMessageManager = require("../Features/SystemMessages/SystemMessageManager")
2016-09-05 10:58:31 -04:00
AuthenticationController = require("../Features/Authentication/AuthenticationController")
_ = require("underscore")
async = require("async")
2014-09-08 10:40:46 -04:00
Modules = require "./Modules"
2016-07-20 11:10:33 -04:00
Url = require "url"
PackageVersions = require "./PackageVersions"
htmlEncoder = new require("node-html-encoder").Encoder("numerical")
hashedFiles = {}
2014-02-12 05:23:40 -05:00
Path = require 'path'
Features = require "./Features"
Modules = require "./Modules"
moment = require 'moment'
2014-02-12 05:23:40 -05:00
jsPath =
if Settings.useMinifiedJs
"/minjs/"
else
"/js/"
ace = PackageVersions.lib('ace')
pdfjs = PackageVersions.lib('pdfjs')
fineuploader = PackageVersions.lib('fineuploader')
2016-07-18 09:05:07 -04:00
getFileContent = (filePath)->
filePath = Path.join __dirname, "../../../", "public#{filePath}"
exists = fs.existsSync filePath
if exists
2017-12-14 07:11:13 -05:00
content = fs.readFileSync filePath, "UTF-8"
return content
else
2017-12-14 07:11:13 -05:00
logger.log filePath:filePath, "file does not exist for hashing"
return ""
pathList = [
2017-12-14 07:11:13 -05:00
"#{jsPath}libs/require.js"
"#{jsPath}ide.js"
"#{jsPath}main.js"
"#{jsPath}libraries.js"
"/stylesheets/style.css"
"/stylesheets/light-style.css"
"/stylesheets/ieee-style.css"
"/stylesheets/sl-style.css"
].concat(Modules.moduleAssetFiles(jsPath))
if !Settings.useMinifiedJs
logger.log "not using minified JS, not hashing static files"
else
logger.log "Generating file hashes..."
for path in pathList
content = getFileContent(path)
hash = crypto.createHash("md5").update(content).digest("hex")
splitPath = path.split("/")
filenameSplit = splitPath.pop().split(".")
filenameSplit.splice(filenameSplit.length-1, 0, hash)
splitPath.push(filenameSplit.join("."))
2017-12-14 07:11:13 -05:00
hashPath = splitPath.join("/")
hashedFiles[path] = hashPath
fsHashPath = Path.join __dirname, "../../../", "public#{hashPath}"
fs.writeFileSync(fsHashPath, content)
2017-12-14 07:11:13 -05:00
logger.log "Finished hashing static content"
2016-07-21 10:34:23 -04:00
cdnAvailable = Settings.cdn?.web?.host?
darkCdnAvailable = Settings.cdn?.web?.darkHost?
2014-02-12 05:23:40 -05:00
2017-07-05 09:32:55 -04:00
module.exports = (app, webRouter, privateApiRouter, publicApiRouter)->
webRouter.use (req, res, next)->
2014-02-12 05:23:40 -05:00
res.locals.session = req.session
next()
addSetContentDisposition = (req, res, next) ->
res.setContentDisposition = (type, opts) ->
directives = for k, v of opts
"#{k}=\"#{encodeURIComponent(v)}\""
contentDispositionValue = "#{type}; #{directives.join('; ')}"
res.setHeader(
'Content-Disposition',
contentDispositionValue
)
next()
webRouter.use addSetContentDisposition
2017-07-05 09:32:55 -04:00
privateApiRouter.use addSetContentDisposition
publicApiRouter.use addSetContentDisposition
webRouter.use (req, res, next)->
req.externalAuthenticationSystemUsed = Features.externalAuthenticationSystemUsed
res.locals.externalAuthenticationSystemUsed = Features.externalAuthenticationSystemUsed
req.hasFeature = res.locals.hasFeature = Features.hasFeature
res.locals.userIsFromOLv1 = (user) ->
user.overleaf?.id?
res.locals.userIsFromSL = (user) ->
!user.overleaf?.id?
next()
2016-09-05 10:58:31 -04:00
webRouter.use (req, res, next)->
2016-07-21 10:34:23 -04:00
2016-08-19 06:05:35 -04:00
cdnBlocked = req.query.nocdn == 'true' or req.session.cdnBlocked
2016-09-22 10:33:50 -04:00
user_id = AuthenticationController.getLoggedInUserId(req)
2016-08-19 06:05:35 -04:00
if cdnBlocked and !req.session.cdnBlocked?
2016-09-22 10:33:50 -04:00
logger.log user_id:user_id, ip:req?.ip, "cdnBlocked for user, not using it and turning it off for future requets"
2016-08-19 06:05:35 -04:00
req.session.cdnBlocked = true
isDark = req.headers?.host?.slice(0,7)?.toLowerCase().indexOf("dark") != -1
2016-07-21 10:34:23 -04:00
isSmoke = req.headers?.host?.slice(0,5)?.toLowerCase() == "smoke"
isLive = !isDark and !isSmoke
2016-08-19 06:53:40 -04:00
2016-08-19 06:05:35 -04:00
if cdnAvailable and isLive and !cdnBlocked
2016-07-21 10:34:23 -04:00
staticFilesBase = Settings.cdn?.web?.host
else if darkCdnAvailable and isDark
staticFilesBase = Settings.cdn?.web?.darkHost
2016-07-21 10:34:23 -04:00
else
staticFilesBase = ""
2016-09-05 10:58:31 -04:00
2014-02-12 05:23:40 -05:00
res.locals.jsPath = jsPath
2016-07-20 11:10:33 -04:00
res.locals.fullJsPath = Url.resolve(staticFilesBase, jsPath)
res.locals.lib = PackageVersions.lib
2016-07-20 07:58:32 -04:00
res.locals.moment = moment
2017-12-13 08:06:38 -05:00
2016-07-19 10:10:07 -04:00
res.locals.buildJsPath = (jsFile, opts = {})->
2016-07-20 11:10:33 -04:00
path = Path.join(jsPath, jsFile)
2016-07-20 07:58:32 -04:00
if opts.hashedPath && hashedFiles[path]?
2017-12-13 08:06:38 -05:00
path = hashedFiles[path]
2016-09-05 10:58:31 -04:00
2016-07-19 10:10:07 -04:00
if !opts.qs?
opts.qs = {}
2016-07-20 07:58:32 -04:00
if opts.cdn != false
path = Url.resolve(staticFilesBase, path)
2016-09-05 10:58:31 -04:00
2016-07-19 10:10:07 -04:00
qs = querystring.stringify(opts.qs)
2016-07-20 07:58:32 -04:00
2017-12-13 09:13:45 -05:00
if opts.removeExtension == true
path = path.slice(0,-3)
2016-07-20 07:58:32 -04:00
if qs? and qs.length > 0
2016-07-20 11:10:33 -04:00
path = path + "?" + qs
return path
res.locals.buildWebpackPath = (jsFile, opts = {}) ->
if Settings.webpack? and !Settings.useMinifiedJs
path = Path.join(jsPath, jsFile)
if opts.removeExtension == true
path = path.slice(0,-3)
return "#{Settings.webpack.url}/public#{path}"
else
2018-03-15 08:15:00 -04:00
return res.locals.buildJsPath(jsFile, opts)
IEEE_BRAND_ID = 15
res.locals.isIEEE = (brandVariation) ->
brandVariation?.brand_id == IEEE_BRAND_ID
_buildCssFileName = (themeModifier) ->
return "/" + Settings.brandPrefix + (if themeModifier then themeModifier else "") + "style.css"
res.locals.getCssThemeModifier = (userSettings, brandVariation) ->
# Themes only exist in OL v2
if Settings.overleaf?
# The IEEE theme takes precedence over the user personal setting, i.e. a user with
# a theme setting of "light" will still get the IEE theme in IEEE branded projects.
if res.locals.isIEEE(brandVariation)
themeModifier = "ieee-"
else if userSettings?.overallTheme?
themeModifier = userSettings.overallTheme
return themeModifier
res.locals.buildCssPath = (themeModifier, buildOpts) ->
cssFileName = _buildCssFileName themeModifier
path = Path.join("/stylesheets/", cssFileName)
if buildOpts?.hashedPath && hashedFiles[path]?
hashedPath = hashedFiles[path]
return Url.resolve(staticFilesBase, hashedPath)
return Url.resolve(staticFilesBase, path)
res.locals.buildImgPath = (imgFile)->
2016-07-21 10:34:23 -04:00
path = Path.join("/img/", imgFile)
2016-07-20 11:10:33 -04:00
return Url.resolve(staticFilesBase, path)
2018-06-27 18:26:39 -04:00
res.locals.mathJaxPath = res.locals.buildJsPath(
'libs/mathjax/MathJax.js',
{cdn:false, qs:{config:'TeX-AMS_HTML,Safe'}}
2018-06-27 18:26:39 -04:00
)
2014-02-12 05:23:40 -05:00
next()
2016-09-05 10:58:31 -04:00
webRouter.use (req, res, next)->
2014-02-12 05:23:40 -05:00
res.locals.settings = Settings
next()
webRouter.use (req, res, next)->
res.locals.translate = (key, vars = {}, htmlEncode = false) ->
vars.appName = Settings.appName
str = req.i18n.translate(key, vars)
if htmlEncode then htmlEncoder.htmlEncode(str) else str
# Don't include the query string parameters, otherwise Google
# treats ?nocdn=true as the canonical version
res.locals.currentUrl = Url.parse(req.originalUrl).pathname
res.locals.capitalize = (string) ->
return "" if string.length == 0
return string.charAt(0).toUpperCase() + string.slice(1)
2014-03-24 13:18:58 -04:00
next()
webRouter.use (req, res, next)->
2014-02-12 05:23:40 -05:00
res.locals.getSiteHost = ->
Settings.siteUrl.substring(Settings.siteUrl.indexOf("//")+2)
next()
2016-09-22 10:33:50 -04:00
webRouter.use (req, res, next) ->
res.locals.getUserEmail = ->
2016-09-22 10:33:50 -04:00
user = AuthenticationController.getSessionUser(req)
email = user?.email or ""
return email
next()
webRouter.use (req, res, next) ->
res.locals.StringHelper = require('../Features/Helpers/StringHelper')
next()
webRouter.use (req, res, next)->
2014-04-07 15:46:58 -04:00
res.locals.formatProjectPublicAccessLevel = (privilegeLevel)->
formatedPrivileges = private:"Private", readOnly:"Public: Read Only", readAndWrite:"Public: Read and Write"
return formatedPrivileges[privilegeLevel] || "Private"
2014-02-12 05:23:40 -05:00
next()
2016-09-05 10:58:31 -04:00
webRouter.use (req, res, next)->
2014-02-12 05:23:40 -05:00
res.locals.buildReferalUrl = (referal_medium) ->
url = Settings.siteUrl
2016-09-22 09:30:34 -04:00
currentUser = AuthenticationController.getSessionUser(req)
if currentUser? and currentUser?.referal_id?
url+="?r=#{currentUser.referal_id}&rm=#{referal_medium}&rs=b" # Referal source = bonus
2014-02-12 05:23:40 -05:00
return url
res.locals.getReferalId = ->
2016-09-22 09:30:34 -04:00
currentUser = AuthenticationController.getSessionUser(req)
if currentUser? and currentUser?.referal_id?
return currentUser.referal_id
2014-02-12 05:23:40 -05:00
res.locals.getReferalTagLine = ->
tagLines = [
"Roar!"
"Shout about us!"
"Please recommend us"
"Tell the world!"
"Thanks for using ShareLaTeX"
]
return tagLines[Math.floor(Math.random()*tagLines.length)]
res.locals.getRedirAsQueryString = ->
if req.query.redir?
return "?#{querystring.stringify({redir:req.query.redir})}"
return ""
res.locals.getLoggedInUserId = ->
2016-09-05 10:58:31 -04:00
return AuthenticationController.getLoggedInUserId(req)
2016-09-06 10:22:13 -04:00
res.locals.isUserLoggedIn = ->
return AuthenticationController.isUserLoggedIn(req)
res.locals.getSessionUser = ->
return AuthenticationController.getSessionUser(req)
2016-11-29 09:38:25 -05:00
2014-02-12 05:23:40 -05:00
next()
webRouter.use (req, res, next) ->
res.locals.csrfToken = req?.csrfToken()
2014-02-12 05:23:40 -05:00
next()
webRouter.use (req, res, next) ->
res.locals.getReqQueryParam = (field)->
return req.query?[field]
next()
2016-09-05 10:58:31 -04:00
webRouter.use (req, res, next)->
2014-02-12 05:23:40 -05:00
res.locals.formatPrice = SubscriptionFormatters.formatPrice
next()
webRouter.use (req, res, next)->
2016-09-22 09:30:34 -04:00
currentUser = AuthenticationController.getSessionUser(req)
if currentUser?
2014-02-12 05:23:40 -05:00
res.locals.user =
2016-09-22 09:30:34 -04:00
email: currentUser.email
first_name: currentUser.first_name
last_name: currentUser.last_name
2014-02-12 05:23:40 -05:00
if req.session.justRegistered
res.locals.justRegistered = true
delete req.session.justRegistered
if req.session.justLoggedIn
res.locals.justLoggedIn = true
delete req.session.justLoggedIn
res.locals.gaToken = Settings.analytics?.ga?.token
res.locals.tenderUrl = Settings.tenderUrl
res.locals.sentrySrc = Settings.sentry?.src
res.locals.sentryPublicDSN = Settings.sentry?.publicDSN
2014-02-12 05:23:40 -05:00
next()
webRouter.use (req, res, next) ->
2014-02-12 05:23:40 -05:00
if req.query? and req.query.scribtex_path?
res.locals.lookingForScribtex = true
res.locals.scribtexPath = req.query.scribtex_path
next()
webRouter.use (req, res, next) ->
# Clone the nav settings so they can be modified for each request
res.locals.nav = {}
for key, value of Settings.nav
res.locals.nav[key] = _.clone(Settings.nav[key])
2014-08-20 09:47:27 -04:00
res.locals.templates = Settings.templateLinks
if res.locals.nav.header
console.error {}, "The `nav.header` setting is no longer supported, use `nav.header_extras` instead"
2014-06-20 16:35:42 -04:00
next()
2016-09-05 10:58:31 -04:00
webRouter.use (req, res, next) ->
2014-07-24 08:24:08 -04:00
SystemMessageManager.getMessages (error, messages = []) ->
res.locals.systemMessages = messages
next()
2014-02-12 05:23:40 -05:00
webRouter.use (req, res, next)->
res.locals.query = req.query
next()
webRouter.use (req, res, next)->
subdomain = _.find Settings.i18n.subdomainLang, (subdomain)->
2014-08-21 12:58:25 -04:00
subdomain.lngCode == req.showUserOtherLng and !subdomain.hide
res.locals.recomendSubdomain = subdomain
res.locals.currentLngCode = req.lng
next()
webRouter.use (req, res, next) ->
if Settings.reloadModuleViewsOnEachRequest
2014-09-08 10:40:46 -04:00
Modules.loadViewIncludes()
res.locals.moduleIncludes = Modules.moduleIncludes
res.locals.moduleIncludesAvailable = Modules.moduleIncludesAvailable
2014-09-08 10:40:46 -04:00
next()
webRouter.use (req, res, next) ->
isSl = (Settings.brandPrefix == 'sl-')
res.locals.uiConfig =
defaultResizerSizeOpen : if isSl then 24 else 7
defaultResizerSizeClosed : if isSl then 24 else 7
eastResizerCursor : if isSl then null else "ew-resize"
westResizerCursor : if isSl then null else "ew-resize"
chatResizerSizeOpen : if isSl then 12 else 7
chatResizerSizeClosed : 0
chatMessageBorderSaturation: if isSl then "70%" else "85%"
chatMessageBorderLightness : if isSl then "70%" else "40%"
chatMessageBgSaturation : if isSl then "60%" else "85%"
chatMessageBgLightness : if isSl then "97%" else "40%"
defaultFontFamily : if isSl then 'monaco' else 'lucida'
defaultLineHeight : if isSl then 'compact' else 'normal'
renderAnnouncements : isSl
next()
2018-08-13 07:13:44 -04:00
2018-08-28 09:12:00 -04:00
webRouter.use (req, res, next) ->
#TODO
2018-08-28 09:12:00 -04:00
if Settings.overleaf?
res.locals.overallThemes = [
{ name: "Default", val: "", path: res.locals.buildCssPath(null, { hashedPath: true }) }
{ name: "Light", val: "light-", path: res.locals.buildCssPath("light-", { hashedPath: true }) }
2018-08-28 09:12:00 -04:00
]
next()
2018-08-13 07:13:44 -04:00
webRouter.use (req, res, next) ->
2018-08-13 07:32:32 -04:00
res.locals.ExposedSettings =
2018-08-13 07:13:44 -04:00
isOverleaf: Settings.overleaf?
2018-10-03 11:40:32 -04:00
appName: Settings.appName
siteUrl: Settings.siteUrl
recaptchaSiteKeyV3: Settings.recaptcha?.siteKeyV3
recaptchaDisabled: Settings.recaptcha?.disabled
2018-08-13 07:32:32 -04:00
next()