diff --git a/typo3/sysext/backend/Classes/Http/AjaxRequestHandler.php b/typo3/sysext/backend/Classes/Http/AjaxRequestHandler.php index cedc02bce0460db697148796e07c50daafa78a7e..e2145c7a3e67d850ae864523728cfbcf1be70c9e 100644 --- a/typo3/sysext/backend/Classes/Http/AjaxRequestHandler.php +++ b/typo3/sysext/backend/Classes/Http/AjaxRequestHandler.php @@ -26,7 +26,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; /** * AJAX dispatcher * - * Main entry point for AJAX calls in the TYPO3 Backend. Based on ?ajaxId of the outside application. + * Main entry point for AJAX calls in the TYPO3 Backend. Based on ?route=/ajax/* of the outside application. * Before doing the basic BE-related set up of this request (see the additional calls on $this->bootstrap inside * handleRequest()), some AJAX-calls can be made without a valid user, which is determined here. * @@ -44,7 +44,7 @@ class AjaxRequestHandler implements RequestHandlerInterface * List of requests that don't need a valid BE user * @var array */ - protected $publicAjaxIds = [ + protected $publicAjaxRoutes = [ '/ajax/login', '/ajax/logout', '/ajax/login/refresh', @@ -70,10 +70,11 @@ class AjaxRequestHandler implements RequestHandlerInterface */ public function handleRequest(ServerRequestInterface $request) { - // First get the ajaxID - $ajaxID = isset($request->getParsedBody()['ajaxID']) ? $request->getParsedBody()['ajaxID'] : $request->getQueryParams()['ajaxID']; - $request = $request->withAttribute('routePath', $ajaxID); - $proceedIfNoUserIsLoggedIn = $this->isLoggedInBackendUserRequired($ajaxID); + // First get the name of the route + $routePath = isset($request->getParsedBody()['route']) ? $request->getParsedBody()['route'] : $request->getQueryParams()['route']; + $request = $request->withAttribute('routePath', $routePath); + + $proceedIfNoUserIsLoggedIn = $this->isLoggedInBackendUserRequired($routePath); $this->boot($proceedIfNoUserIsLoggedIn); // Backend Routing - check if a valid route is there, and dispatch @@ -82,14 +83,15 @@ class AjaxRequestHandler implements RequestHandlerInterface /** * This request handler can handle any backend request having - * an ajaxID as parameter (see Application.php in EXT:backend) + * an /ajax/ request * * @param ServerRequestInterface $request * @return bool If the request is an AJAX backend request, TRUE otherwise FALSE */ public function canHandleRequest(ServerRequestInterface $request) { - return $request->getAttribute('isAjaxRequest', false); + $routePath = isset($request->getParsedBody()['route']) ? $request->getParsedBody()['route'] : $request->getQueryParams()['route']; + return strpos($routePath, '/ajax/') === 0; } /** @@ -106,12 +108,12 @@ class AjaxRequestHandler implements RequestHandlerInterface * Check if the user is required for the request * If we're trying to do an ajax login, don't require a user * - * @param string $ajaxId the Ajax ID to check against + * @param string $routePath the Route path to check against, something like ' * @return bool whether the request can proceed without a login required */ - protected function isLoggedInBackendUserRequired($ajaxId) + protected function isLoggedInBackendUserRequired($routePath) { - return in_array($ajaxId, $this->publicAjaxIds, true); + return in_array($routePath, $this->publicAjaxRoutes, true); } /** diff --git a/typo3/sysext/backend/Classes/Http/Application.php b/typo3/sysext/backend/Classes/Http/Application.php index 859e382e4b2ff62274a2f7b29ea50097b5134341..683a1b35f0ddfe09d9b57f4155fcc7282d165c68 100644 --- a/typo3/sysext/backend/Classes/Http/Application.php +++ b/typo3/sysext/backend/Classes/Http/Application.php @@ -59,7 +59,7 @@ class Application implements ApplicationInterface $this->bootstrap = Bootstrap::getInstance() ->initializeClassLoader($classLoader) - ->setRequestType(TYPO3_REQUESTTYPE_BE | (!empty($_GET['ajaxID']) ? TYPO3_REQUESTTYPE_AJAX : 0)) + ->setRequestType(TYPO3_REQUESTTYPE_BE | (isset($_REQUEST['route']) && strpos($_REQUEST['route'], '/ajax/') === 0 ? TYPO3_REQUESTTYPE_AJAX : 0)) ->baseSetup($this->entryPointLevel); // Redirect to install tool if base configuration is not found @@ -82,10 +82,7 @@ class Application implements ApplicationInterface public function run(callable $execute = null) { $this->request = \TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals(); - // see below when this option is set and Bootstrap::defineTypo3RequestTypes() for more details - if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) { - $this->request = $this->request->withAttribute('isAjaxRequest', true); - } elseif (isset($this->request->getQueryParams()['M'])) { + if (isset($this->request->getQueryParams()['M'])) { $this->request = $this->request->withAttribute('isModuleRequest', true); } diff --git a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php index 66a32b8a11b1adf33b987f68117c273b1aed5fa2..957f85c785c7a09eed65abbafa46fdb7983942af 100644 --- a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php +++ b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php @@ -78,12 +78,8 @@ class RouteDispatcher extends Dispatcher implements DispatcherInterface $route = $request->getAttribute('route'); if ($route->getOption('access') === 'public') { return true; - } elseif ($route->getOption('ajax')) { - $token = (string)(isset($request->getParsedBody()['ajaxToken']) ? $request->getParsedBody()['ajaxToken'] : $request->getQueryParams()['ajaxToken']); - return $this->getFormProtection()->validateToken($token, 'ajaxCall', $route->getOption('_identifier')); - } else { - $token = (string)(isset($request->getParsedBody()['token']) ? $request->getParsedBody()['token'] : $request->getQueryParams()['token']); - return $this->getFormProtection()->validateToken($token, 'route', $route->getOption('_identifier')); } + $token = (string)(isset($request->getParsedBody()['token']) ? $request->getParsedBody()['token'] : $request->getQueryParams()['token']); + return $this->getFormProtection()->validateToken($token, 'route', $route->getOption('_identifier')); } } diff --git a/typo3/sysext/backend/Classes/Routing/UriBuilder.php b/typo3/sysext/backend/Classes/Routing/UriBuilder.php index 7f546e5015be362193ca767df46f3538689d4108..93e5fadabb38a5672ff999e38de37f0ec0d426da 100644 --- a/typo3/sysext/backend/Classes/Routing/UriBuilder.php +++ b/typo3/sysext/backend/Classes/Routing/UriBuilder.php @@ -79,34 +79,18 @@ class UriBuilder $parameters ); - // The Route is an AJAX route, so the parameters are different in order - // for the AjaxRequestHandler to be triggered - if ($route->getOption('ajax')) { - // If the route has the "public" option set, no token is generated. - if ($route->getOption('access') !== 'public') { - $parameters = [ - 'ajaxToken' => FormProtectionFactory::get('backend')->generateToken('ajaxCall', $name) - ] + $parameters; - } - - // Add the Route path as &ajaxID=XYZ - $parameters = [ - 'ajaxID' => $route->getPath() - ] + $parameters; - } else { - // If the route has the "public" option set, no token is generated. - if ($route->getOption('access') !== 'public') { - $parameters = [ - 'token' => FormProtectionFactory::get('backend')->generateToken('route', $name) - ] + $parameters; - } - - // Add the Route path as &route=XYZ + // If the route has the "public" option set, no token is generated. + if ($route->getOption('access') !== 'public') { $parameters = [ - 'route' => $route->getPath() + 'token' => FormProtectionFactory::get('backend')->generateToken('route', $name) ] + $parameters; } + // Add the Route path as &route=XYZ + $parameters = [ + 'route' => $route->getPath() + ] + $parameters; + return $this->buildUri($parameters, $referenceType); } diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js b/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js index 13074e4441846c710e888e1c753f9c61239edbf4..2f1db7452ba5b93dd82491a2b41c55c4ad13e76b 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js @@ -107,7 +107,7 @@ define(['jquery'], function($) { }; Tree = { - ajaxID: 'sc_alt_file_navframe_expandtoggle', + ajaxRoute: 'sc_alt_file_navframe_expandtoggle', frameSetModule: null, activateDragDrop: true, highlightClass: 'active', @@ -133,7 +133,7 @@ define(['jquery'], function($) { $obj.css({cursor: 'wait'}); } $.ajax({ - url: TYPO3.settings.ajaxUrls[this.ajaxID], + url: TYPO3.settings.ajaxUrls[this.ajaxRoute], data: { PM: params, scopeData: scopeData, diff --git a/typo3/sysext/backend/Tests/Unit/Routing/UriBuilderTest.php b/typo3/sysext/backend/Tests/Unit/Routing/UriBuilderTest.php index 667c3487a63c7d746509697d02557b5c74e4b155..e4cf27da1fcdcb69678eb337b8a0eb82ed3b72e1 100644 --- a/typo3/sysext/backend/Tests/Unit/Routing/UriBuilderTest.php +++ b/typo3/sysext/backend/Tests/Unit/Routing/UriBuilderTest.php @@ -57,7 +57,7 @@ class UriBuilderTest extends UnitTestCase [ 'route' => new Route('/test/route', [ 'ajax' => true ]) ], 'route', [], - '/typo3/index.php?ajaxID=%2Ftest%2Froute&ajaxToken=dummyToken', + '/typo3/index.php?route=%2Ftest%2Froute&token=dummyToken', ], 'plain route with default parameters' => [ [ 'route' => new Route('/test/route', [ 'parameters' => [ 'key' => 'value' ] ]) ], @@ -69,7 +69,7 @@ class UriBuilderTest extends UnitTestCase [ 'route' => new Route('/test/route', [ 'ajax' => true, 'parameters' => [ 'key' => 'value' ] ]) ], 'route', [], - '/typo3/index.php?ajaxID=%2Ftest%2Froute&ajaxToken=dummyToken&key=value', + '/typo3/index.php?route=%2Ftest%2Froute&token=dummyToken&key=value', ], 'plain route with overridden parameters' => [ [ 'route' => new Route('/test/route', [ 'parameters' => [ 'key' => 'value' ] ]) ], @@ -81,7 +81,7 @@ class UriBuilderTest extends UnitTestCase [ 'route' => new Route('/test/route', [ 'ajax' => true, 'parameters' => [ 'key' => 'value' ] ]) ], 'route', ['key' => 'overridden'], - '/typo3/index.php?ajaxID=%2Ftest%2Froute&ajaxToken=dummyToken&key=overridden', + '/typo3/index.php?route=%2Ftest%2Froute&token=dummyToken&key=overridden', ], ]; } diff --git a/typo3/sysext/core/Documentation/Changelog/master/Important-81899-BackendAJAXRoutesUseRouteajaxInsteadOfAjaxIdParameter.rst b/typo3/sysext/core/Documentation/Changelog/master/Important-81899-BackendAJAXRoutesUseRouteajaxInsteadOfAjaxIdParameter.rst new file mode 100644 index 0000000000000000000000000000000000000000..e5c9fbe065cedb2ab80c6fb8740355f56a1dd621 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Important-81899-BackendAJAXRoutesUseRouteajaxInsteadOfAjaxIdParameter.rst @@ -0,0 +1,18 @@ +.. include:: ../../Includes.txt + +========================================================================================= +Important: #81899 - Backend AJAX routes use "&route=/ajax/" instead of "ajaxId" parameter +========================================================================================= + +See :issue:`81899` + +Description +=========== + +The TYPO3 Backend uses AJAX calls by calling routes with the ``&route=/ajax/*`` GET/POST parameter +now instead of the "&ajaxId" GET/POST parameter. + +Although this is not a breaking change, some PHP code might rely on GET/POST parameters being +set, and must check for the route parameter instead. + +.. index:: Backend \ No newline at end of file