‪TYPO3CMS  10.4
FileDumpController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
36 
41 {
45  protected ‪$resourceFactory;
46 
48  {
49  $this->resourceFactory = ‪$resourceFactory;
50  }
51 
62  public function ‪dumpAction(ServerRequestInterface $request): ResponseInterface
63  {
64  $parameters = $this->‪buildParametersFromRequest($request);
65 
66  if (!$this->‪isTokenValid($parameters, $request)) {
67  return (new ‪Response())->withStatus(403);
68  }
69  $file = $this->‪createFileObjectByParameters($parameters);
70  if ($file === null) {
71  return (new Response())->withStatus(404);
72  }
73 
74  // Hook: allow some other process to do some security/access checks. Hook should return 403 response if access is rejected, void otherwise
75  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['FileDumpEID.php']['checkFileAccess'] ?? [] as $className) {
76  $hookObject = GeneralUtility::makeInstance($className);
77  if (!$hookObject instanceof FileDumpEIDHookInterface) {
78  throw new \UnexpectedValueException($className . ' must implement interface ' . FileDumpEIDHookInterface::class, 1394442417);
79  }
80  $response = $hookObject->checkFileAccess($file);
81  if ($response instanceof ResponseInterface) {
82  return $this->‪applyContentSecurityPolicy($file, $response);
83  }
84  }
85 
86  $processingInstructions = [];
87 
88  // Apply cropping, if possible
89  if (!empty($parameters['cv'])) {
90  $cropVariant = $parameters['cv'];
91  $cropString = $file instanceof FileReference ? $file->getProperty('crop') : '';
92  $cropArea = ‪CropVariantCollection::create((string)$cropString)->‪getCropArea($cropVariant);
93  $processingInstructions = array_merge(
94  $processingInstructions,
95  [
96  'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($file),
97  ]
98  );
99  }
100 
101  // Apply width/height, if given
102  if (!empty($parameters['s'])) {
103  $size = ‪GeneralUtility::trimExplode(':', $parameters['s']);
104  $processingInstructions = array_merge(
105  $processingInstructions,
106  [
107  'width' => $size[0] ?? null,
108  'height' => $size[1] ?? null,
109  'minWidth' => $size[2] ? (int)$size[2] : null,
110  'minHeight' => $size[3] ? (int)$size[3] : null,
111  'maxWidth' => $size[4] ? (int)$size[4] : null,
112  'maxHeight' => $size[5] ? (int)$size[5] : null
113  ]
114  );
115  }
116 
117  if (!empty($processingInstructions) && !($file instanceof ProcessedFile)) {
118  if (is_callable([$file, 'getOriginalFile'])) {
119  // Get the original file from the file reference
120  $file = $file->getOriginalFile();
121  }
122  $file = $file->process(‪ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingInstructions);
123  }
124 
125  return $this->‪applyContentSecurityPolicy(
126  $file,
127  $file->getStorage()->streamFile($file)
128  );
129  }
130 
131  protected function ‪buildParametersFromRequest(ServerRequestInterface $request): array
132  {
133  $parameters = ['eID' => 'dumpFile'];
134  $queryParams = $request->getQueryParams();
135  // Identifier of what to process. f, r or p
136  // Only needed while hash_equals
137  $t = (string)($queryParams['t'] ?? '');
138  if ($t) {
139  $parameters['t'] = $t;
140  }
141  // sys_file
142  $f = (string)($queryParams['f'] ?? '');
143  if ($f) {
144  $parameters['f'] = (int)$f;
145  }
146  // sys_file_reference
147  $r = (string)($queryParams['r'] ?? '');
148  if ($r) {
149  $parameters['r'] = (int)$r;
150  }
151  // Processed file
152  $p = (string)($queryParams['p'] ?? '');
153  if ($p) {
154  $parameters['p'] = (int)$p;
155  }
156  // File's width and height in this order: w:h:minW:minH:maxW:maxH
157  $s = (string)($queryParams['s'] ?? '');
158  if ($s) {
159  $parameters['s'] = $s;
160  }
161  // File's crop variant
162  $v = (string)($queryParams['cv'] ?? '');
163  if ($v) {
164  $parameters['cv'] = (string)$v;
165  }
166 
167  return $parameters;
168  }
169 
170  protected function ‪isTokenValid(array $parameters, ServerRequestInterface $request): bool
171  {
172  return hash_equals(
173  GeneralUtility::hmac(implode('|', $parameters), 'resourceStorageDumpFile'),
174  $request->getQueryParams()['token'] ?? ''
175  );
176  }
177 
182  protected function ‪createFileObjectByParameters(array $parameters)
183  {
184  $file = null;
185  if (isset($parameters['f'])) {
186  try {
187  $file = $this->resourceFactory->getFileObject($parameters['f']);
188  if ($file->isDeleted() || $file->isMissing() || !$this->isFileValid($file)) {
189  $file = null;
190  }
191  } catch (\Exception $e) {
192  $file = null;
193  }
194  } elseif (isset($parameters['r'])) {
195  try {
196  $file = $this->resourceFactory->getFileReferenceObject($parameters['r']);
197  if ($file->isMissing() || !$this->isFileValid($file->getOriginalFile())) {
198  $file = null;
199  }
200  } catch (\Exception $e) {
201  $file = null;
202  }
203  } elseif (isset($parameters['p'])) {
204  try {
205  $processedFileRepository = GeneralUtility::makeInstance(ProcessedFileRepository::class);
207  $file = $processedFileRepository->findByUid($parameters['p']);
208  if (!$file || $file->isDeleted() || !$this->isFileValid($file->getOriginalFile())) {
209  $file = null;
210  }
211  } catch (\Exception $e) {
212  $file = null;
213  }
214  }
215  return $file;
216  }
217 
218  protected function ‪isFileValid(‪FileInterface $file): bool
219  {
220  return $file->‪getStorage()->‪getDriverType() !== 'Local'
221  || GeneralUtility::makeInstance(FileNameValidator::class)
222  ->isValid(basename($file->‪getIdentifier()));
223  }
224 
228  protected function ‪applyContentSecurityPolicy(‪ResourceInterface $file, ResponseInterface $response): ResponseInterface
229  {
230  $extension = ‪PathUtility::pathinfo($file->‪getName(), PATHINFO_EXTENSION);
231  // same as in `typo3/sysext/install/Resources/Private/FolderStructureTemplateFiles/resources-root-htaccess`
232  if ($extension === 'pdf' || $response->getHeaderLine('content-type') === 'application/pdf') {
233  $policy = "default-src 'self' 'unsafe-inline'; script-src 'none'; object-src 'self'; plugin-types application/pdf;";
234  } elseif ($extension === 'svg' || $response->getHeaderLine('content-type') === 'image/svg+xml') {
235  $policy = "default-src 'self'; script-src 'none'; style-src 'unsafe-inline'; object-src 'none';";
236  } else {
237  $policy = "default-src 'self'; script-src 'none'; style-src 'none'; object-src 'none';";
238  }
239  return $response->withAddedHeader('content-security-policy', $policy);
240  }
241 }
‪TYPO3\CMS\Core\Resource\ProcessedFileRepository
Definition: ProcessedFileRepository.php:30
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:24
‪TYPO3\CMS\Core\Resource\Hook\FileDumpEIDHookInterface
Definition: FileDumpEIDHookInterface.php:26
‪TYPO3\CMS\Core\Controller\FileDumpController\createFileObjectByParameters
‪File FileReference ProcessedFile null createFileObjectByParameters(array $parameters)
Definition: FileDumpController.php:181
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:22
‪TYPO3\CMS\Core\Resource\ResourceStorage\getDriverType
‪string getDriverType()
Definition: ResourceStorage.php:2865
‪TYPO3\CMS\Core\Controller\FileDumpController\$resourceFactory
‪ResourceFactory $resourceFactory
Definition: FileDumpController.php:44
‪TYPO3\CMS\Core\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Core\Resource\Security\FileNameValidator
Definition: FileNameValidator.php:25
‪TYPO3\CMS\Core\Controller\FileDumpController\isFileValid
‪isFileValid(FileInterface $file)
Definition: FileDumpController.php:217
‪TYPO3\CMS\Core\Controller\FileDumpController\isTokenValid
‪isTokenValid(array $parameters, ServerRequestInterface $request)
Definition: FileDumpController.php:169
‪TYPO3\CMS\Core\Resource\ProcessedFile\CONTEXT_IMAGECROPSCALEMASK
‪const CONTEXT_IMAGECROPSCALEMASK
Definition: ProcessedFile.php:58
‪TYPO3\CMS\Core\Resource\FileReference\getProperty
‪mixed getProperty($key)
Definition: FileReference.php:118
‪TYPO3\CMS\Core\Controller\FileDumpController\__construct
‪__construct(ResourceFactory $resourceFactory)
Definition: FileDumpController.php:46
‪TYPO3\CMS\Core\Controller\FileDumpController\buildParametersFromRequest
‪buildParametersFromRequest(ServerRequestInterface $request)
Definition: FileDumpController.php:130
‪TYPO3\CMS\Core\Resource\FileReference
Definition: FileReference.php:33
‪TYPO3\CMS\Core\Controller
Definition: ErrorPageController.php:18
‪TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
Definition: FileDoesNotExistException.php:22
‪TYPO3\CMS\Core\Resource\ResourceInterface\getIdentifier
‪string getIdentifier()
‪TYPO3\CMS\Core\Resource\ResourceInterface\getStorage
‪ResourceStorage getStorage()
‪TYPO3\CMS\Core\Controller\FileDumpController\dumpAction
‪ResponseInterface dumpAction(ServerRequestInterface $request)
Definition: FileDumpController.php:61
‪TYPO3\CMS\Core\Controller\FileDumpController
Definition: FileDumpController.php:41
‪TYPO3\CMS\Core\Http\Response
Definition: Response.php:30
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:41
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:24
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection\getCropArea
‪Area getCropArea(string $id='default')
Definition: CropVariantCollection.php:129
‪TYPO3\CMS\Core\Utility\PathUtility\pathinfo
‪static string string[] pathinfo($path, $options=null)
Definition: PathUtility.php:208
‪TYPO3\CMS\Core\Resource\ResourceInterface\getName
‪string getName()
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:44
‪TYPO3\CMS\Core\Controller\FileDumpController\applyContentSecurityPolicy
‪applyContentSecurityPolicy(ResourceInterface $file, ResponseInterface $response)
Definition: FileDumpController.php:227
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection
Definition: CropVariantCollection.php:23
‪TYPO3\CMS\Core\Resource\ResourceInterface
Definition: ResourceInterface.php:22
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection\create
‪static CropVariantCollection create(string $jsonString, array $tcaConfig=[])
Definition: CropVariantCollection.php:42