Sfoglia il codice sorgente

[web] Add `window.` prefix to globals and add `no-restricted-globals` rule (#26422)

* Add `no-restricted-globals` eslint rule

Co-authored-by: Rebeka <rebeka.dekany@overleaf.com>

* Change `self` to `window.self`

* Change `innerWidth` to `window.innerWidth`

* Change `confirm` to `window.confirm`

* Change `location` to `window.location`

* Use `location` from `useLocation` hook

* Use location from useLocation hook
Co-authored-by: Antoine <antoine.clausse@overleaf.com>

* Disable no-restricted-globals eslint rule for use of 'self'

* Use `confusing-browser-globals` from npm

* Prevent unexpected globals in workers, using `no-undef`

* Use `self` as a global in workers

* Use unexpected globals in workers, using `no-restricted-globals` in workers

---------

Co-authored-by: Rebeka <rebeka.dekany@overleaf.com>
Co-authored-by: Rebeka <o.dekany@gmail.com>
GitOrigin-RevId: 526986799f5f2edf53c7d978fa85c1e98189565f
Antoine Clausse 1 anno fa
parent
commit
46555d27b0

+ 22 - 0
package-lock.json

@@ -18024,6 +18024,13 @@
         "proto-list": "~1.2.1"
         "proto-list": "~1.2.1"
       }
       }
     },
     },
+    "node_modules/confusing-browser-globals": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
+      "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/connect-flash": {
     "node_modules/connect-flash": {
       "version": "0.1.1",
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
       "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
@@ -45366,6 +45373,7 @@
         "chartjs-plugin-datalabels": "^2.2.0",
         "chartjs-plugin-datalabels": "^2.2.0",
         "cheerio": "^1.0.0-rc.3",
         "cheerio": "^1.0.0-rc.3",
         "classnames": "^2.2.6",
         "classnames": "^2.2.6",
+        "confusing-browser-globals": "^1.0.11",
         "cookie-signature": "^1.2.1",
         "cookie-signature": "^1.2.1",
         "copy-webpack-plugin": "^11.0.0",
         "copy-webpack-plugin": "^11.0.0",
         "core-js": "^3.41.0",
         "core-js": "^3.41.0",
@@ -45392,6 +45400,7 @@
         "formik": "^2.2.9",
         "formik": "^2.2.9",
         "fuse.js": "^3.0.0",
         "fuse.js": "^3.0.0",
         "glob": "^7.1.6",
         "glob": "^7.1.6",
+        "globals": "^16.2.0",
         "handlebars": "^4.7.8",
         "handlebars": "^4.7.8",
         "handlebars-loader": "^1.7.3",
         "handlebars-loader": "^1.7.3",
         "html-webpack-plugin": "^5.5.3",
         "html-webpack-plugin": "^5.5.3",
@@ -46342,6 +46351,19 @@
         "node": ">=18.11.0"
         "node": ">=18.11.0"
       }
       }
     },
     },
+    "services/web/node_modules/globals": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
+      "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "services/web/node_modules/google-auth-library": {
     "services/web/node_modules/google-auth-library": {
       "version": "8.7.0",
       "version": "8.7.0",
       "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.7.0.tgz",
       "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.7.0.tgz",

+ 17 - 0
services/web/.eslintrc.js

@@ -1,3 +1,7 @@
+const _ = require('lodash')
+const confusingBrowserGlobals = require('confusing-browser-globals')
+const globals = require('globals')
+
 module.exports = {
 module.exports = {
   root: true,
   root: true,
   parser: '@typescript-eslint/parser',
   parser: '@typescript-eslint/parser',
@@ -19,6 +23,7 @@ module.exports = {
   },
   },
   rules: {
   rules: {
     'no-constant-binary-expression': 'error',
     'no-constant-binary-expression': 'error',
+    'no-restricted-globals': ['error', ...confusingBrowserGlobals],
 
 
     // do not allow importing of implicit dependencies.
     // do not allow importing of implicit dependencies.
     'import/no-extraneous-dependencies': 'error',
     'import/no-extraneous-dependencies': 'error',
@@ -531,5 +536,17 @@ module.exports = {
         'no-console': 'error',
         'no-console': 'error',
       },
       },
     },
     },
+    {
+      files: ['**/*.worker.{js,ts}'],
+      rules: {
+        'no-restricted-globals': [
+          'error',
+          ..._.difference(
+            Object.keys({ ...globals.browser, ...globals.node }),
+            Object.keys(globals.worker)
+          ),
+        ],
+      },
+    },
   ],
   ],
 }
 }

+ 2 - 0
services/web/frontend/js/features/settings/components/emails/add-secondary-email-prompt.tsx

@@ -8,6 +8,7 @@ import MaterialIcon from '@/shared/components/material-icon'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { ReCaptcha2 } from '../../../../shared/components/recaptcha-2'
 import { ReCaptcha2 } from '../../../../shared/components/recaptcha-2'
 import { useRecaptcha } from '../../../../shared/hooks/use-recaptcha'
 import { useRecaptcha } from '../../../../shared/hooks/use-recaptcha'
+import { useLocation } from '@/shared/hooks/use-location'
 
 
 import { postJSON } from '../../../../infrastructure/fetch-json'
 import { postJSON } from '../../../../infrastructure/fetch-json'
 import RecaptchaConditions from '@/shared/components/recaptcha-conditions'
 import RecaptchaConditions from '@/shared/components/recaptcha-conditions'
@@ -25,6 +26,7 @@ export function AddSecondaryEmailPrompt() {
   const [error, setError] = useState<AddSecondaryEmailError | undefined>()
   const [error, setError] = useState<AddSecondaryEmailError | undefined>()
   const [isSubmitting, setIsSubmitting] = useState<boolean>(false)
   const [isSubmitting, setIsSubmitting] = useState<boolean>(false)
   const { ref: recaptchaRef, getReCaptchaToken } = useRecaptcha()
   const { ref: recaptchaRef, getReCaptchaToken } = useRecaptcha()
+  const location = useLocation()
 
 
   if (!isReady) {
   if (!isReady) {
     return null
     return null

+ 2 - 0
services/web/frontend/js/features/settings/components/emails/confirm-email-form.tsx

@@ -9,6 +9,7 @@ import MaterialIcon from '@/shared/components/material-icon'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { sendMB } from '@/infrastructure/event-tracking'
 import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
 import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
+import { useLocation } from '@/shared/hooks/use-location'
 
 
 type Feedback = {
 type Feedback = {
   type: 'input' | 'alert'
   type: 'input' | 'alert'
@@ -267,6 +268,7 @@ function ConfirmEmailSuccessfullForm({
   successButtonText: string
   successButtonText: string
   redirectTo: string
   redirectTo: string
 }) {
 }) {
+  const location = useLocation()
   const submitHandler = (e: FormEvent<HTMLFormElement>) => {
   const submitHandler = (e: FormEvent<HTMLFormElement>) => {
     e.preventDefault()
     e.preventDefault()
     location.assign(redirectTo)
     location.assign(redirectTo)

+ 5 - 3
services/web/frontend/js/features/token-access/components/sharing-updates-root.tsx

@@ -12,6 +12,7 @@ import { sendMB } from '@/infrastructure/event-tracking'
 
 
 import LeaveProjectModal from './leave-project-modal'
 import LeaveProjectModal from './leave-project-modal'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
+import { useLocation } from '@/shared/hooks/use-location'
 
 
 function SharingUpdatesRoot() {
 function SharingUpdatesRoot() {
   const [showModal, setShowModal] = useState(false)
   const [showModal, setShowModal] = useState(false)
@@ -20,6 +21,7 @@ function SharingUpdatesRoot() {
   const { isLoading, isSuccess, isError, runAsync } = useAsync()
   const { isLoading, isSuccess, isError, runAsync } = useAsync()
   const projectId = getMeta('ol-project_id')
   const projectId = getMeta('ol-project_id')
 
 
+  const location = useLocation()
   const joinProject = useCallback(() => {
   const joinProject = useCallback(() => {
     sendMB('notification-click', {
     sendMB('notification-click', {
       name: 'link-sharing-collaborator',
       name: 'link-sharing-collaborator',
@@ -30,7 +32,7 @@ function SharingUpdatesRoot() {
         location.assign(`/project/${projectId}`)
         location.assign(`/project/${projectId}`)
       })
       })
       .catch(debugConsole.error)
       .catch(debugConsole.error)
-  }, [runAsync, projectId])
+  }, [runAsync, projectId, location])
 
 
   const viewProject = useCallback(() => {
   const viewProject = useCallback(() => {
     sendMB('notification-click', {
     sendMB('notification-click', {
@@ -42,7 +44,7 @@ function SharingUpdatesRoot() {
         location.assign(`/project/${projectId}`)
         location.assign(`/project/${projectId}`)
       })
       })
       .catch(debugConsole.error)
       .catch(debugConsole.error)
-  }, [runAsync, projectId])
+  }, [runAsync, projectId, location])
 
 
   const leaveProject = useCallback(() => {
   const leaveProject = useCallback(() => {
     sendMB('notification-click', {
     sendMB('notification-click', {
@@ -54,7 +56,7 @@ function SharingUpdatesRoot() {
         location.assign('/project')
         location.assign('/project')
       })
       })
       .catch(debugConsole.error)
       .catch(debugConsole.error)
-  }, [runAsync, projectId])
+  }, [runAsync, projectId, location])
 
 
   if (!isReady) {
   if (!isReady) {
     return null
     return null

+ 1 - 1
services/web/frontend/js/infrastructure/error-reporter.ts

@@ -78,7 +78,7 @@ function sentryReporter() {
               const refererUrl = new URL(event.request.headers.Referer)
               const refererUrl = new URL(event.request.headers.Referer)
 
 
               if (
               if (
-                refererUrl.hostname === location.hostname &&
+                refererUrl.hostname === window.location.hostname &&
                 refererUrl.pathname.startsWith('/read/')
                 refererUrl.pathname.startsWith('/read/')
               ) {
               ) {
                 refererUrl.pathname = '/read/'
                 refererUrl.pathname = '/read/'

+ 2 - 0
services/web/package.json

@@ -278,6 +278,7 @@
     "chartjs-plugin-datalabels": "^2.2.0",
     "chartjs-plugin-datalabels": "^2.2.0",
     "cheerio": "^1.0.0-rc.3",
     "cheerio": "^1.0.0-rc.3",
     "classnames": "^2.2.6",
     "classnames": "^2.2.6",
+    "confusing-browser-globals": "^1.0.11",
     "cookie-signature": "^1.2.1",
     "cookie-signature": "^1.2.1",
     "copy-webpack-plugin": "^11.0.0",
     "copy-webpack-plugin": "^11.0.0",
     "core-js": "^3.41.0",
     "core-js": "^3.41.0",
@@ -304,6 +305,7 @@
     "formik": "^2.2.9",
     "formik": "^2.2.9",
     "fuse.js": "^3.0.0",
     "fuse.js": "^3.0.0",
     "glob": "^7.1.6",
     "glob": "^7.1.6",
+    "globals": "^16.2.0",
     "handlebars": "^4.7.8",
     "handlebars": "^4.7.8",
     "handlebars-loader": "^1.7.3",
     "handlebars-loader": "^1.7.3",
     "html-webpack-plugin": "^5.5.3",
     "html-webpack-plugin": "^5.5.3",