Răsfoiți Sursa

Update `req.i18n.translate` to contains better filtering security and inject `appName` variable by default to all translation keys (#11312)

Also remove the unused translate wrapper function since the content has been imported directly in the `req.i18n.translate`

GitOrigin-RevId: ed9cee76783e4d41819845a82f66afaed47e2ebd
M Fahru 3 ani în urmă
părinte
comite
811b224d81

+ 0 - 34
services/web/app/src/Features/Helpers/Translate.js

@@ -1,34 +0,0 @@
-const Settings = require('@overleaf/settings')
-const pug = require('pug-runtime')
-const logger = require('@overleaf/logger')
-const SafeHTMLSubstitute = require('./SafeHTMLSubstitution')
-const I18N_HTML_INJECTIONS = new Set()
-
-function translate(key, req, vars, components) {
-  vars = vars || {}
-
-  if (Settings.i18n.checkForHTMLInVars) {
-    Object.entries(vars).forEach(([field, value]) => {
-      if (pug.escape(value) !== value) {
-        const violationsKey = key + field
-        // do not flood the logs, log one sample per pod + key + field
-        if (!I18N_HTML_INJECTIONS.has(violationsKey)) {
-          logger.warn(
-            { key, field, value },
-            'html content in translations context vars'
-          )
-          I18N_HTML_INJECTIONS.add(violationsKey)
-        }
-      }
-    })
-  }
-
-  vars.appName = Settings.appName
-  const locale = req.i18n.translate(key, vars)
-  if (components) {
-    return SafeHTMLSubstitute.render(locale, components)
-  } else {
-    return locale
-  }
-}
-module.exports = { translate }

+ 2 - 3
services/web/app/src/infrastructure/ExpressLocals.js

@@ -18,7 +18,6 @@ const {
 const {
   addOptionalCleanupHandlerAfterDrainingConnections,
 } = require('./GracefulShutdown')
-const { translate } = require('../Features/Helpers/Translate')
 
 const IEEE_BRAND_ID = Settings.ieeeBrandId
 
@@ -227,8 +226,8 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
   })
 
   webRouter.use(function (req, res, next) {
-    res.locals.translate = (key, vars, components) =>
-      translate(key, req, vars, components)
+    res.locals.translate = req.i18n.translate
+
     // Don't include the query string parameters, otherwise Google
     // treats ?nocdn=true as the canonical version
     const parsedOriginalUrl = new URL(req.originalUrl, Settings.siteUrl)

+ 36 - 1
services/web/app/src/infrastructure/Translations.js

@@ -4,11 +4,16 @@ const middleware = require('i18next-http-middleware')
 const path = require('path')
 const Settings = require('@overleaf/settings')
 const { URL } = require('url')
+const pug = require('pug-runtime')
+const logger = require('@overleaf/logger')
+const SafeHTMLSubstitution = require('../Features/Helpers/SafeHTMLSubstitution')
 
 const fallbackLanguageCode = Settings.i18n.defaultLng || 'en'
 const availableLanguageCodes = []
 const availableHosts = new Map()
 const subdomainConfigs = new Map()
+const I18N_HTML_INJECTIONS = new Set()
+
 Object.values(Settings.i18n.subdomainLang || {}).forEach(function (spec) {
   availableLanguageCodes.push(spec.lngCode)
   // prebuild a host->lngCode mapping for the usage at runtime in the
@@ -50,6 +55,10 @@ i18n
       // Disable nesting in interpolated values, preventing user input
       // injection via another nested value
       skipOnVariables: true,
+
+      defaultVariables: {
+        appName: Settings.appName,
+      },
     },
 
     preload: availableLanguageCodes,
@@ -83,7 +92,33 @@ function setLangBasedOnDomainMiddleware(req, res, next) {
 
   // Decorate req.i18n with translate function alias for backwards
   // compatibility usage in requests
-  req.i18n.translate = req.i18n.t
+  req.i18n.translate = (key, vars, components) => {
+    vars = vars || {}
+
+    if (Settings.i18n.checkForHTMLInVars) {
+      Object.entries(vars).forEach(([field, value]) => {
+        if (pug.escape(value) !== value) {
+          const violationsKey = key + field
+          // do not flood the logs, log one sample per pod + key + field
+          if (!I18N_HTML_INJECTIONS.has(violationsKey)) {
+            logger.warn(
+              { key, field, value },
+              'html content in translations context vars'
+            )
+            I18N_HTML_INJECTIONS.add(violationsKey)
+          }
+        }
+      })
+    }
+
+    const locale = req.i18n.t(key, vars)
+    if (components) {
+      return SafeHTMLSubstitution.render(locale, components)
+    } else {
+      return locale
+    }
+  }
+
   next()
 }