From 7c5d08bda7b0ec61cc12aa6e9acde1fafe6d0922 Mon Sep 17 00:00:00 2001
From: Oliver Hader <oliver@typo3.org>
Date: Mon, 29 Nov 2021 15:36:58 +0100
Subject: [PATCH] [TASK] Deprecate inline JavaScript in backend update signals

Deprecates BackendUtility::getUpdateSignalCode as well as using
custom singal callbacks providing `JScode` containing inline JavaScript.

Resolves: #96136
Releases: main
Change-Id: I1462625ac3aee2a71da3956f79a6ffde6d620be5
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72373
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: Benjamin Franzke <bfr@qbus.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
---
 .../Classes/Template/ModuleTemplate.php       |   2 +-
 .../Classes/Utility/BackendUtility.php        |  18 ++-
 ...InlineJavaScriptInBackendUpdateSignals.rst | 122 ++++++++++++++++++
 .../Php/MethodCallStaticMatcher.php           |   7 +
 4 files changed, 144 insertions(+), 5 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-96136-DeprecateInlineJavaScriptInBackendUpdateSignals.rst

diff --git a/typo3/sysext/backend/Classes/Template/ModuleTemplate.php b/typo3/sysext/backend/Classes/Template/ModuleTemplate.php
index e110286961e9..e0358bc1a475 100644
--- a/typo3/sysext/backend/Classes/Template/ModuleTemplate.php
+++ b/typo3/sysext/backend/Classes/Template/ModuleTemplate.php
@@ -401,7 +401,7 @@ class ModuleTemplate
                 implode("\n", $updateSignalDetails['html'])
             );
         }
-        // @todo deprecate inline JavaScript in TYPO3 v12.0
+        // @deprecated will be removed in TYPO3 v13.0
         if (!empty($updateSignalDetails['script'])) {
             $this->pageRenderer->addJsFooterInlineCode(
                 'updateSignals',
diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php
index 3ecffca87524..60a14b3628a7 100644
--- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php
+++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php
@@ -2438,10 +2438,15 @@ class BackendUtility
      *
      * @return string HTML javascript code
      * @see BackendUtility::setUpdateSignal()
-     * @internal use getUpdateSignalDetails() instead, will be deprecated in TYPO3 v12.0
+     * @deprecated will be removed in TYPO3 v13.0, use getUpdateSignalDetails() instead
      */
     public static function getUpdateSignalCode()
     {
+        trigger_error(
+            'BackendUtility::getUpdateSignalCode will be removed in TYPO3 v13.0, use BackendUtility::getUpdateSignalDetails instead.',
+            E_USER_DEPRECATED
+        );
+
         $signals = [];
         $modData = static::getBackendUserAuthentication()->getModuleData(
             BackendUtility::class . '::getUpdateSignal',
@@ -2505,7 +2510,7 @@ class BackendUtility
     {
         $details = [
             'html' => [],
-            // @todo deprecate inline JavaScript in TYPO3 v12.0
+            // @deprecated `script` will be removed in TYPO3 v13.0
             'script' => [],
         ];
         $modData = static::getBackendUserAuthentication()->getModuleData(
@@ -2523,11 +2528,16 @@ class BackendUtility
                 $params = ['set' => $set, 'parameter' => $val['parameter'], 'JScode' => '', 'html' => ''];
                 $ref = null;
                 GeneralUtility::callUserFunction($updateSignals[$set], $params, $ref);
-                // @todo verify and adjust documentation
                 if (!empty($params['html'])) {
                     $details['html'][] = $params['html'];
                 } elseif (!empty($params['JScode'])) {
-                    // @todo deprecate in TYPO3 v12.0, avoid inline JavaScript
+                    trigger_error(
+                        sprintf(
+                            'Using `JScode` in update signal "%s" will be removed in TYPO3 v13.0, use `html` instead.',
+                            $set
+                        ),
+                        E_USER_DEPRECATED
+                    );
                     $details['script'][] = $params['JScode'];
                 }
             } else {
diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-96136-DeprecateInlineJavaScriptInBackendUpdateSignals.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-96136-DeprecateInlineJavaScriptInBackendUpdateSignals.rst
new file mode 100644
index 000000000000..95e78a86f0a7
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-96136-DeprecateInlineJavaScriptInBackendUpdateSignals.rst
@@ -0,0 +1,122 @@
+.. include:: ../../Includes.txt
+
+===========================================================================
+Deprecation: #96136 - Deprecate inline JavaScript in backend update signals
+===========================================================================
+
+See :issue:`96136`
+
+Description
+===========
+
+When changing data via the backend user interface a so called *update signal*
+is triggered to update other components like page tree or toolbar items in the
+document header bar.
+
+Using inline JavaScript for handing custom signals is deprecated and will be
+ignored in TYPO3 v13.0.
+
+
+Impact
+======
+
+Retrieving signals via :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignalCode`
+or having custom signal callbacks defined in :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['updateSignalHook']`
+which provide `JScode` are deprecated and will trigger a corresponding PHP
+error message.
+
+
+Affected Installations
+======================
+
+see impact
+
+
+Migration
+=========
+
+`BackendUtility::getUpdateSignalCode`
+-------------------------------------
+
+In case :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignalCode`
+is called directly, new :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignalDetails`
+shall be used, which is supposed to return safe HTML markup instead of inline
+JavaScript code.
+
+Custom signal callbacks
+-----------------------
+
+Usually those custom signal hooks are declared like this:
+
+.. code-block:: php
+
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']
+        ['updateSignalHook']['OpendocsController::updateNumber'] =
+        OpendocsToolbarItem::class . '->updateNumberOfOpenDocsHook';
+
+Existing implementation using `JScode`
+......................................
+
+.. code-block:: php
+
+    class OpendocsToolbarItem
+    {
+        public function updateNumberOfOpenDocsHook(&$params)
+        {
+            $params['JScode'] = '
+                if (top && top.TYPO3.OpendocsMenu) {
+                    top.TYPO3.OpendocsMenu.updateMenu();
+                }
+            ';
+        }
+    }
+
+Using :php:`JScode` (containing inline JavaScript) is deprecated and
+is subject to be migrated.
+
+Potential migration using HTML markup
+.....................................
+
+TYPO3 v11 introduced some special markup helpers and components that
+allow to dispatch actions, without actually using inline JavaScript.
+
+* :php:`\TYPO3\CMS\Backend\Domain\Model\Element\ImmediateActionElement`,
+  which creates a HTML web-component containing the actual relevant payload like
+  :html:`<typo3-immediate-action action="..." args="..."></typo3-immediate-action>`
+* :php:`\TYPO3\CMS\Core\Page\JavaScriptModuleInstruction` rendered using
+  :php:`\TYPO3\CMS\Core\Page\JavaScriptRenderer::render`, which uses a script helper
+  that loads JavaScript modules and invokes a method or assigns variables globally, e.g.
+  :html:`<script src="/typo3/sysext/core/Resources/Public/JavaScript/JavaScriptHandler.js" ...>`
+
+**Side-note**: Just using markup like :html:`<script>alert(1)</script>`
+is **not** considered a good solution as it still contains inline JavaScript.
+
+.. code-block:: php
+
+    class OpendocsToolbarItem
+    {
+        public function updateNumberOfOpenDocsHook(&$params)
+        {
+            $params['html'] = ImmediateActionElement::dispatchCustomEvent(
+                'typo3:opendocs:updateRequested',
+                null,
+                true
+            );
+        }
+    }
+
+:php:`ImmediateActionElement` is utilized to trigger a custom event in JavaScript,
+which is handled by a custom JavaScript module in that particular case.
+
+.. code-block:: typescript
+
+    class OpendocsMenu {
+      constructor() {
+        document.addEventListener(
+          'typo3:opendocs:updateRequested',
+          (evt: CustomEvent) => this.updateMenu(),
+        );
+      }
+
+
+.. index:: Backend, JavaScript, FullyScanned, ext:backend
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
index 04af38604fb1..13072834f2a1 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
@@ -105,6 +105,13 @@ return [
             'Deprecation-79341-MethodsRelatedToRichtextConfiguration.rst',
         ],
     ],
+    'TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignalCode' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-96136-DeprecateInlineJavaScriptInBackendUpdateSignals.rst',
+        ],
+    ],
     'TYPO3\CMS\Core\DataHandling\DataHandler::rmComma' => [
         'numberOfMandatoryArguments' => 1,
         'maximumNumberOfArguments' => 1,
-- 
GitLab