[SECURITY] Respect permissions of storages in a file collection
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Service / UserFileMountService.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Service;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
18 use TYPO3\CMS\Core\Messaging\FlashMessage;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * Service class for implementing the user filemounts,
23 * used for BE_USER (\TYPO3\CMS\Core\Authentication\BackendUserAuthentication)
24 * and TCEforms hooks
25 *
26 * Note: This is now also used by sys_file_category table (fieldname "folder")!
27 */
28 class UserFileMountService
29 {
30 /**
31 * User function for sys_filemounts (the userfilemounts)
32 * to render a dropdown for selecting a folder
33 * of a selected mount
34 *
35 * @param array $PA the array with additional configuration options.
36 */
37 public function renderTceformsSelectDropdown(&$PA)
38 {
39 $allowedStorageIds = array_map(
40 function(\TYPO3\CMS\Core\Resource\ResourceStorage $storage) {
41 return $storage->getUid();
42 },
43 $this->getBackendUserAuthentication()->getFileStorages()
44 );
45 // If working for sys_filemounts table
46 $storageUid = (int)$PA['row']['base'][0];
47 if (!$storageUid) {
48 // If working for sys_file_collection table
49 $storageUid = (int)$PA['row']['storage'][0];
50 }
51 if ($storageUid > 0 && in_array($storageUid, $allowedStorageIds, true)) {
52 /** @var $storageRepository \TYPO3\CMS\Core\Resource\StorageRepository */
53 $storageRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\StorageRepository::class);
54 /** @var $storage \TYPO3\CMS\Core\Resource\ResourceStorage */
55 $storage = $storageRepository->findByUid($storageUid);
56 if ($storage === null) {
57 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */
58 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
59 $queue = $flashMessageService->getMessageQueueByIdentifier();
60 $queue->enqueue(new FlashMessage('Storage #' . $storageUid . ' does not exist. No folder is currently selectable.', '', FlashMessage::ERROR));
61 if (empty($PA['items'])) {
62 $PA['items'][] = [
63 $PA['row'][$PA['field']],
64 $PA['row'][$PA['field']]
65 ];
66 }
67 } elseif ($storage->isBrowsable()) {
68 $rootLevelFolders = [];
69
70 $fileMounts = $storage->getFileMounts();
71 if (!empty($fileMounts)) {
72 foreach ($fileMounts as $fileMountInfo) {
73 $rootLevelFolders[] = $fileMountInfo['folder'];
74 }
75 } else {
76 $rootLevelFolders[] = $storage->getRootLevelFolder();
77 }
78
79 foreach ($rootLevelFolders as $rootLevelFolder) {
80 $folderItems = $this->getSubfoldersForOptionList($rootLevelFolder);
81 foreach ($folderItems as $item) {
82 $PA['items'][] = [
83 $item->getIdentifier(),
84 $item->getIdentifier()
85 ];
86 }
87 }
88 } else {
89 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */
90 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
91 $queue = $flashMessageService->getMessageQueueByIdentifier();
92 $queue->enqueue(new FlashMessage('Storage "' . $storage->getName() . '" is not browsable. No folder is currently selectable.', '', FlashMessage::WARNING));
93 if (empty($PA['items'])) {
94 $PA['items'][] = [
95 $PA['row'][$PA['field']],
96 $PA['row'][$PA['field']]
97 ];
98 }
99 }
100 } else {
101 $PA['items'][] = ['', 'Please choose a FAL mount from above first.'];
102 }
103 }
104
105 /**
106 * Simple function to make a hierarchical subfolder request into
107 * a "flat" option list
108 *
109 * @param \TYPO3\CMS\Core\Resource\Folder $parentFolder
110 * @param int $level a limiter
111 * @return \TYPO3\CMS\Core\Resource\Folder[]
112 */
113 protected function getSubfoldersForOptionList(\TYPO3\CMS\Core\Resource\Folder $parentFolder, $level = 0)
114 {
115 $level++;
116 // hard break on recursion
117 if ($level > 99) {
118 return [];
119 }
120 $allFolderItems = [$parentFolder];
121 $subFolders = $parentFolder->getSubfolders();
122 foreach ($subFolders as $subFolder) {
123 try {
124 $subFolderItems = $this->getSubfoldersForOptionList($subFolder, $level);
125 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderReadPermissionsException $e) {
126 $subFolderItems = [];
127 }
128 $allFolderItems = array_merge($allFolderItems, $subFolderItems);
129 }
130 return $allFolderItems;
131 }
132
133 /**
134 * Returns the BE USER Object
135 *
136 * @return BackendUserAuthentication
137 */
138 protected function getBackendUserAuthentication()
139 {
140 return $GLOBALS['BE_USER'];
141 }
142 }