[TASK] Ensure HTTP RequestHandlers always return a PSR-7 Repsonse
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Http / InstallerRequestHandler.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Install\Http;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
21 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
22 use TYPO3\CMS\Core\FormProtection\InstallToolFormProtection;
23 use TYPO3\CMS\Core\Http\JsonResponse;
24 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
25 use TYPO3\CMS\Install\Controller\InstallerController;
26 use TYPO3\CMS\Install\Service\EnableFileService;
27 use TYPO3\CMS\Install\Service\SessionService;
28
29 /**
30 * Request handler to walk through the web installation process of TYPO3
31 */
32 class InstallerRequestHandler implements RequestHandlerInterface
33 {
34 /**
35 * Handles an install tool request when nothing is there
36 *
37 * @param ServerRequestInterface $request
38 * @return ResponseInterface
39 * @throws \RuntimeException
40 */
41 public function handleRequest(ServerRequestInterface $request): ResponseInterface
42 {
43 $controller = new InstallerController();
44 $actionName = $request->getParsedBody()['install']['action'] ?? $request->getQueryParams()['install']['action'] ?? 'init';
45 $action = $actionName . 'Action';
46
47 if ($actionName === 'init' || $actionName === 'mainLayout') {
48 $response = $controller->$action();
49 } elseif ($actionName === 'checkInstallerAvailable') {
50 $response = new JsonResponse([
51 'success' => $this->isInstallerAvailable(),
52 ]);
53 } elseif ($actionName === 'showInstallerNotAvailable') {
54 $response = $controller->showInstallerNotAvailableAction();
55 } elseif ($actionName === 'checkEnvironmentAndFolders'
56 || $actionName === 'showEnvironmentAndFolders'
57 || $actionName === 'executeEnvironmentAndFolders'
58 ) {
59 $this->throwIfInstallerIsNotAvailable();
60 $response = $controller->$action($request);
61 } else {
62 $this->throwIfInstallerIsNotAvailable();
63 // With main folder layout available, sessions can be handled
64 $session = new SessionService();
65 if (!$session->hasSession()) {
66 $session->startSession();
67 }
68 if ($session->isExpired()) {
69 $session->refreshSession();
70 }
71 $postValues = $request->getParsedBody()['install'];
72 $sessionTokenOk = false;
73 if (empty($postValues)) {
74 // No post data is there, no token check necessary
75 $sessionTokenOk = true;
76 }
77 if (isset($postValues['token'])) {
78 // A token must be given as soon as there is POST data
79 $formProtection = FormProtectionFactory::get(InstallToolFormProtection::class);
80 if ($actionName === '') {
81 throw new \RuntimeException('No POST action given for token check', 1505647681);
82 }
83 $sessionTokenOk = $formProtection->validateToken($postValues['token'], 'installTool', $actionName);
84 }
85 if (!$sessionTokenOk) {
86 $session->resetSession();
87 $session->startSession();
88 throw new \RuntimeException('Invalid session token', 1505647737);
89 }
90
91 if (!method_exists($controller, $action)) {
92 // Sanitize action method, preventing injecting whatever method name
93 throw new \RuntimeException(
94 'Unknown action method ' . $action . ' in controller InstallerController',
95 1505687700
96 );
97 }
98
99 $response = $controller->$action($request);
100
101 if ($actionName === 'executeDefaultConfiguration') {
102 // Executing last step cleans session
103 $session->destroySession();
104 }
105 }
106
107 return $response;
108 }
109
110 /**
111 * First installation is in progress, if LocalConfiguration does not exist,
112 * or if FIRST_INSTALL file exists.
113 *
114 * @param ServerRequestInterface $request
115 * @return bool Returns always TRUE
116 */
117 public function canHandleRequest(ServerRequestInterface $request): bool
118 {
119 $localConfigurationFileLocation = (new ConfigurationManager())->getLocalConfigurationFileLocation();
120 return !@is_file($localConfigurationFileLocation) || EnableFileService::isFirstInstallAllowed();
121 }
122
123 /**
124 * Returns the priority - how eager the handler is to actually handle the request.
125 *
126 * @return int The priority of the request handler.
127 */
128 public function getPriority(): int
129 {
130 return 20;
131 }
132
133 /**
134 * @throws \RuntimeException If installer is not available due to missing FIRST_INSTALL
135 */
136 protected function throwIfInstallerIsNotAvailable()
137 {
138 if (!$this->isInstallerAvailable()) {
139 throw new \RuntimeException(
140 'Installer not available',
141 1505637427
142 );
143 }
144 }
145
146 /**
147 * @return bool TRUE if FIRST_INSTALL file exists
148 */
149 protected function isInstallerAvailable(): bool
150 {
151 if (EnableFileService::isFirstInstallAllowed()) {
152 return true;
153 }
154 return false;
155 }
156 }