1
|
|
|
<?php |
2
|
|
|
namespace Fab\Media\Security; |
3
|
|
|
|
4
|
|
|
/* |
5
|
|
|
* This file is part of the Fab/Media project under GPLv2 or later. |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please read the |
8
|
|
|
* LICENSE.md file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
use Fab\Media\Module\MediaModule; |
12
|
|
|
use Fab\Media\Module\VidiModule; |
13
|
|
|
use Fab\Vidi\Module\ModuleLoader; |
14
|
|
|
use Fab\Vidi\Persistence\ConstraintContainer; |
15
|
|
|
use Fab\Vidi\Service\DataService; |
16
|
|
|
use Fab\Vidi\Utility\BackendUtility; |
17
|
|
|
use TYPO3\CMS\Core\Resource\Folder; |
18
|
|
|
use TYPO3\CMS\Core\Resource\ResourceFactory; |
19
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
20
|
|
|
use Fab\Vidi\Persistence\Matcher; |
21
|
|
|
use Fab\Vidi\Persistence\Query; |
22
|
|
|
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Class which handle signal slot for Vidi Content controller |
26
|
|
|
*/ |
27
|
|
|
class FilePermissionsAspect |
28
|
|
|
{ |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Post-process the matcher object to respect the file storages. |
32
|
|
|
* |
33
|
|
|
* @param Matcher $matcher |
34
|
|
|
* @param string $dataType |
35
|
|
|
* @return void |
36
|
|
|
* @throws \InvalidArgumentException |
37
|
|
|
*/ |
38
|
|
|
public function addFilePermissionsForFileStorages(Matcher $matcher, $dataType) |
39
|
|
|
{ |
40
|
|
|
if ($dataType === 'sys_file' && $this->isPermissionNecessary()) { |
41
|
|
|
|
42
|
|
|
if ($this->isFolderConsidered()) { |
43
|
|
|
|
44
|
|
|
$folder = $this->getMediaModule()->getCurrentFolder(); |
45
|
|
|
|
46
|
|
|
if ($this->getMediaModule()->hasRecursiveSelection()) { |
47
|
|
|
|
48
|
|
|
// Only add like condition if needed. |
49
|
|
|
if ($folder->getStorage()->getRootLevelFolder() !== $folder) { |
50
|
|
|
$matcher->like('identifier', $folder->getIdentifier() . '%', $automaticallyAddWildCard = false); |
51
|
|
|
} |
52
|
|
|
} else { |
53
|
|
|
|
54
|
|
|
// Browse only currently |
55
|
|
|
$files = $this->getFileUids($folder); |
56
|
|
|
$matcher->in('uid', $files); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
$matcher->equals('storage', $folder->getStorage()->getUid()); |
60
|
|
|
} else { |
61
|
|
|
$storage = $this->getMediaModule()->getCurrentStorage(); |
62
|
|
|
|
63
|
|
|
// Set the storage identifier only if the storage is on-line. |
64
|
|
|
$identifier = -1; |
65
|
|
|
if ($storage->isOnline()) { |
66
|
|
|
$identifier = $storage->getUid(); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
if ($this->getModuleLoader()->hasPlugin() && !$this->getCurrentBackendUser()->isAdmin()) { |
70
|
|
|
|
71
|
|
|
$fileMounts = $this->getCurrentBackendUser()->getFileMountRecords(); |
72
|
|
|
$collectedFiles = []; |
73
|
|
|
foreach ($fileMounts as $fileMount) { |
74
|
|
|
|
75
|
|
|
$combinedIdentifier = $fileMount['base'] . ':' . $fileMount['path']; |
76
|
|
|
$folder = ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($combinedIdentifier); |
77
|
|
|
|
78
|
|
|
$files = $this->getFileUids($folder); |
79
|
|
|
$collectedFiles = array_merge($collectedFiles, $files); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$matcher->in('uid', $collectedFiles); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
$matcher->equals('storage', $identifier); |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @return bool |
92
|
|
|
*/ |
93
|
|
|
protected function isPermissionNecessary() |
94
|
|
|
{ |
95
|
|
|
|
96
|
|
|
$isNecessary = true; |
97
|
|
|
|
98
|
|
|
$parameters = GeneralUtility::_GET(VidiModule::getParameterPrefix()); |
99
|
|
|
|
100
|
|
View Code Duplication |
if ($parameters['controller'] === 'Clipboard' && ($parameters['action'] === 'show' || $parameters['action'] === 'flush')) { |
|
|
|
|
101
|
|
|
$isNecessary = false; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
View Code Duplication |
if ($parameters['controller'] === 'Content' && ($parameters['action'] === 'copyClipboard' || $parameters['action'] === 'moveClipboard')) { |
|
|
|
|
105
|
|
|
$isNecessary = false; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
return $isNecessary; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @return bool |
113
|
|
|
*/ |
114
|
|
|
protected function isFolderConsidered() |
115
|
|
|
{ |
116
|
|
|
return $this->getMediaModule()->hasFolderTree() && !$this->getModuleLoader()->hasPlugin(); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* @param Folder $folder |
121
|
|
|
* @return array |
122
|
|
|
*/ |
123
|
|
|
protected function getFileUids(Folder $folder) |
124
|
|
|
{ |
125
|
|
|
$files = []; |
126
|
|
|
foreach ($folder->getFiles() as $file) { |
127
|
|
|
$files[] = $file->getUid(); |
128
|
|
|
} |
129
|
|
|
return $files; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Post-process the constraints object to respect the file mounts. |
134
|
|
|
* |
135
|
|
|
* @param Query $query |
136
|
|
|
* @param ConstraintInterface|null $constraints |
137
|
|
|
* @param ConstraintContainer $constraintContainer |
138
|
|
|
* @throws \InvalidArgumentException |
139
|
|
|
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException |
140
|
|
|
*/ |
141
|
|
|
public function addFilePermissionsForFileMounts(Query $query, $constraints, ConstraintContainer $constraintContainer) |
142
|
|
|
{ |
143
|
|
|
if ($query->getType() === 'sys_file') { |
144
|
|
|
if (!$this->getCurrentBackendUser()->isAdmin()) { |
145
|
|
|
$this->respectFileMounts($query, $constraints, $constraintContainer); |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param Query $query |
152
|
|
|
* @param ConstraintInterface|null $constraints |
153
|
|
|
* @param ConstraintContainer $constraintContainer |
154
|
|
|
* @return array |
155
|
|
|
* @throws \InvalidArgumentException |
156
|
|
|
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException |
157
|
|
|
*/ |
158
|
|
|
protected function respectFileMounts(Query $query, $constraints, ConstraintContainer $constraintContainer) |
159
|
|
|
{ |
160
|
|
|
$tableName = 'sys_filemounts'; |
161
|
|
|
|
162
|
|
|
// Get the file mount identifiers for the current Backend User. |
163
|
|
|
$fileMounts = GeneralUtility::trimExplode(',', $this->getCurrentBackendUser()->dataLists['filemount_list']); |
164
|
|
|
$fileMountUids = implode(',', array_filter($fileMounts)); |
165
|
|
|
|
166
|
|
|
// Fetch the records. |
167
|
|
|
$fileMountRecords = $this->getDataService()->getRecords( |
168
|
|
|
$tableName, |
169
|
|
|
[ |
170
|
|
|
'uid' => $fileMountUids |
171
|
|
|
] |
172
|
|
|
); |
173
|
|
|
$constraintsRespectingFileMounts = []; |
174
|
|
|
foreach ((array)$fileMountRecords as $fileMountRecord) { |
175
|
|
|
if ($fileMountRecord['path']) { |
176
|
|
|
$constraintsRespectingFileMounts[] = $query->like( |
177
|
|
|
'identifier', |
178
|
|
|
$fileMountRecord['path'] . '%' |
179
|
|
|
); |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
$logicalOrForRespectingFileMounts = $query->logicalOr($constraintsRespectingFileMounts); |
184
|
|
|
|
185
|
|
|
if ($constraints) { |
186
|
|
|
$constraints = $query->logicalAnd( |
187
|
|
|
$constraints, |
188
|
|
|
$logicalOrForRespectingFileMounts |
189
|
|
|
); |
190
|
|
|
} else { |
191
|
|
|
$constraints = $logicalOrForRespectingFileMounts; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
$constraintContainer->setConstraint($constraints); |
195
|
|
|
|
196
|
|
|
return [$query, $constraints, $constraintContainer]; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication |
201
|
|
|
*/ |
202
|
|
|
protected function getCurrentBackendUser() |
203
|
|
|
{ |
204
|
|
|
return $GLOBALS['BE_USER']; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @return object|DataService |
209
|
|
|
*/ |
210
|
|
|
protected function getDataService(): DataService |
211
|
|
|
{ |
212
|
|
|
return GeneralUtility::makeInstance(DataService::class); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* @return MediaModule|object |
217
|
|
|
* @throws \InvalidArgumentException |
218
|
|
|
*/ |
219
|
|
|
protected function getMediaModule() |
220
|
|
|
{ |
221
|
|
|
return GeneralUtility::makeInstance(MediaModule::class); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Get the Vidi Module Loader. |
226
|
|
|
* |
227
|
|
|
* @return object|ModuleLoader |
228
|
|
|
*/ |
229
|
|
|
protected function getModuleLoader() |
230
|
|
|
{ |
231
|
|
|
return GeneralUtility::makeInstance(ModuleLoader::class); |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.