‪TYPO3CMS  ‪main
FilePermissionAspect.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 
25 use ‪TYPO3\CMS\Core\SysLog\Action\Database as SystemLogDatabaseAction;
26 use ‪TYPO3\CMS\Core\SysLog\Error as SystemLogErrorClassification;
29 
41 {
43 
45  {
46  $this->resourceFactory = ‪$resourceFactory ?? GeneralUtility::makeInstance(ResourceFactory::class);
47  }
48 
56  public function ‪checkModifyAccessList(&$accessAllowed, $table, ‪DataHandler $parent): void
57  {
58  $isInternalProcess = $parent->isImporting || $parent->bypassAccessCheckForRecords;
59  if ($table === 'sys_file' && !$isInternalProcess) {
60  $accessAllowed = false;
61  }
62  }
63 
75  public function ‪processDatamap_preProcessFieldArray(&$incomingFieldArray, string $table, $id, ‪DataHandler $dataHandler): void
76  {
77  if (!is_array($incomingFieldArray) || !is_scalar($id)) {
78  $incomingFieldArray = null;
79  return;
80  }
81  $isInternalProcess = $dataHandler->isImporting || $dataHandler->bypassAccessCheckForRecords;
83  $logId = $isNew ? 0 : (int)$id;
84  if ($table === 'sys_file') {
85  $file = $this->‪resolveFile((int)$id);
86  if (!$this->‪isValidStorageData($incomingFieldArray)
87  || (!$isNew && $file !== null && $this->‪usesLegacyStorage($file))
88  ) {
89  $incomingFieldArray = null;
90  $this->‪logError($table, $logId, 'Attempt to set legacy storage directly is disallowed', $dataHandler);
91  }
92  } elseif ($table === 'sys_file_reference') {
93  $files = $this->‪resolveReferencedFiles($incomingFieldArray, 'uid_local');
94  foreach ($files as $file) {
95  if ($file === null) {
96  $incomingFieldArray = null;
97  $this->‪logError($table, $logId, 'Attempt to reference invalid file is disallowed', $dataHandler);
98  } elseif ($this->‪usesLegacyStorage($file)) {
99  $incomingFieldArray = null;
100  $this->‪logError($table, $logId, sprintf('Attempt to reference file "%d" in legacy storage is disallowed', $file->getUid()), $dataHandler);
101  } elseif (!$isInternalProcess && $this->‪usesDisallowedFileMount($file, 'read', $dataHandler->BE_USER)) {
102  $incomingFieldArray = null;
103  $this->‪logError($table, $logId, sprintf('Attempt to reference file "%d" without permission is disallowed', $file->getUid()), $dataHandler);
104  }
105  }
106  } elseif ($table === 'sys_file_metadata') {
107  $file = $this->‪resolveReferencedFile($incomingFieldArray, 'file');
108  if ($file !== null && $this->‪usesLegacyStorage($file)) {
109  $incomingFieldArray = null;
110  $this->‪logError($table, $logId, sprintf('Attempt to alter metadata of file "%d" in legacy storage is disallowed', $file->getUid()), $dataHandler);
111  } elseif (!$isInternalProcess && $file !== null && $this->‪usesDisallowedFileMount($file, 'editMeta', $dataHandler->BE_USER)) {
112  $incomingFieldArray = null;
113  $this->‪logError($table, $logId, sprintf('Attempt to alter metadata of file "%d" without permission is disallowed', $file->getUid()), $dataHandler);
114  }
115  }
116  }
117 
118  protected function ‪logError(string $table, int $id, string $message, ‪DataHandler $dataHandler): void
119  {
120  $dataHandler->‪log(
121  $table,
122  $id,
123  SystemLogDatabaseAction::UPDATE,
124  0,
125  SystemLogErrorClassification::USER_ERROR,
126  $message,
127  1,
128  [$table]
129  );
130  }
131 
132  protected function ‪usesLegacyStorage(‪File $file): bool
133  {
134  return $file->‪getStorage()->‪getUid() === 0;
135  }
136 
142  protected function ‪usesDisallowedFileMount(‪File $file, string $fileAction, mixed $backendUser): bool
143  {
144  // strict: disallow, in case it cannot be determined from BE_USER
145  if (!$backendUser instanceof ‪BackendUserAuthentication) {
146  return true;
147  }
148  foreach ($backendUser->getFileStorages() as $storage) {
149  if ($storage->getUid() === $file->‪getStorage()->‪getUid()) {
150  return !$storage->checkFileActionPermission($fileAction, $file);
151  }
152  }
153  return false;
154  }
155 
159  protected function ‪resolveReferencedFiles(array $data, string $propertyName): array
160  {
161  $propertyItems = ‪GeneralUtility::trimExplode(',', (string)($data[$propertyName] ?? ''), true);
162  return array_map(
163  function (string $item): ?‪File {
165  return $this->‪resolveFile((int)$item);
166  }
167  if (preg_match('/^sys_file_(?P<fileId>\d+)$/', $item, $matches) && (int)$matches['fileId'] > 0) {
168  return $this->‪resolveFile((int)$matches['fileId']);
169  }
170  return null;
171  },
172  $propertyItems
173  );
174  }
175 
176  protected function ‪resolveReferencedFile(array $data, string $propertyName): ?‪File
177  {
178  $propertyValue = $data[$propertyName] ?? null;
179  if ($propertyValue === null || !‪MathUtility::canBeInterpretedAsInteger($propertyValue)) {
180  return null;
181  }
182  return $this->‪resolveFile((int)$propertyValue);
183  }
184 
185  protected function ‪resolveFile(int $fileId): ?‪File
186  {
187  try {
188  return $this->resourceFactory->getFileObject($fileId);
189  } catch (\Throwable $t) {
190  return null;
191  }
192  }
193 
194  protected function ‪isValidStorageData(array $data): bool
195  {
196  $storage = $data['storage'] ?? '';
198  return false;
199  }
200  return (int)$storage > 0;
201  }
202 }
‪TYPO3\CMS\Core\DataHandling\DataHandler
Definition: DataHandler.php:94
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\usesLegacyStorage
‪usesLegacyStorage(File $file)
Definition: FilePermissionAspect.php:132
‪TYPO3\CMS\Core\Resource\Security
Definition: FileMetadataPermissionsAspect.php:16
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\resolveReferencedFiles
‪list<?File > resolveReferencedFiles(array $data, string $propertyName)
Definition: FilePermissionAspect.php:159
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect
Definition: FilePermissionAspect.php:41
‪TYPO3\CMS\Core\SysLog\Action\Database
Definition: Database.php:24
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\__construct
‪__construct(ResourceFactory $resourceFactory=null)
Definition: FilePermissionAspect.php:44
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\checkModifyAccessList
‪checkModifyAccessList(&$accessAllowed, $table, DataHandler $parent)
Definition: FilePermissionAspect.php:56
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\$resourceFactory
‪ResourceFactory $resourceFactory
Definition: FilePermissionAspect.php:42
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Core\Resource\AbstractFile\getStorage
‪int< 0, getSize():int { if( $this->deleted) { throw new \RuntimeException( 'File has been deleted.', 1329821480);} if(empty( $this->properties[ 'size'])) { $fileInfo=$this-> getStorage() -> getFileInfoByIdentifier($this->getIdentifier(), ['size'])
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:42
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:26
‪TYPO3\CMS\Core\SysLog\Error
Definition: Error.php:24
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\resolveFile
‪resolveFile(int $fileId)
Definition: FilePermissionAspect.php:185
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Resource\AbstractFile\getUid
‪return MathUtility::canBeInterpretedAsInteger($size) ?(int) $size int getUid()
Definition: AbstractFile.php:195
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\resolveReferencedFile
‪resolveReferencedFile(array $data, string $propertyName)
Definition: FilePermissionAspect.php:176
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\isValidStorageData
‪isValidStorageData(array $data)
Definition: FilePermissionAspect.php:194
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\usesDisallowedFileMount
‪bool usesDisallowedFileMount(File $file, string $fileAction, mixed $backendUser)
Definition: FilePermissionAspect.php:142
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\DataHandling\DataHandlerCheckModifyAccessListHookInterface
Definition: DataHandlerCheckModifyAccessListHookInterface.php:22
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\DataHandling\DataHandler\log
‪int log($table, $recuid, $action, $recpid, $error, $details, $details_nr=-1, $data=[], $event_pid=-1, $NEWid='')
Definition: DataHandler.php:9133
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\processDatamap_preProcessFieldArray
‪processDatamap_preProcessFieldArray(&$incomingFieldArray, string $table, $id, DataHandler $dataHandler)
Definition: FilePermissionAspect.php:75
‪TYPO3\CMS\Core\Resource\Security\FilePermissionAspect\logError
‪logError(string $table, int $id, string $message, DataHandler $dataHandler)
Definition: FilePermissionAspect.php:118