[CLEANUP] The correct case must be used for standard PHP types in phpdoc
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Security / FileMetadataPermissionsAspect.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Security;
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\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\DataHandling\DataHandler;
19 use TYPO3\CMS\Core\DataHandling\DataHandlerCheckModifyAccessListHookInterface;
20 use TYPO3\CMS\Core\Resource\ResourceFactory;
21 use TYPO3\CMS\Core\SingletonInterface;
22 use TYPO3\CMS\Core\Utility\MathUtility;
23
24 /**
25 * We do not have AOP in TYPO3 for now, thus the aspect which
26 * deals with file metadata data security is an assembly of hooks to
27 * check permissions on files belonging to file meta data records
28 */
29 class FileMetadataPermissionsAspect implements DataHandlerCheckModifyAccessListHookInterface, SingletonInterface
30 {
31 /**
32 * This hook is called before any write operation by DataHandler
33 *
34 * @param string $table
35 * @param int $id
36 * @param array $fileMetadataRecord
37 * @param int|null $otherHookGrantedAccess
38 * @param \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler
39 * @return int|null
40 */
41 public function checkRecordUpdateAccess($table, $id, $fileMetadataRecord, $otherHookGrantedAccess, DataHandler $dataHandler)
42 {
43 $accessAllowed = $otherHookGrantedAccess;
44 if ($table === 'sys_file_metadata' && $accessAllowed !== 0) {
45 $existingFileMetadataRecord = BackendUtility::getRecord('sys_file_metadata', $id);
46 if ($existingFileMetadataRecord === null || (empty($existingFileMetadataRecord['file']) && !empty($fileMetadataRecord['file']))) {
47 $existingFileMetadataRecord = $fileMetadataRecord;
48 }
49 $accessAllowed = $this->checkFileWriteAccessForFileMetaData($existingFileMetadataRecord) ? 1 : 0;
50 }
51
52 return $accessAllowed;
53 }
54
55 /**
56 * Hook that determines whether a user has access to modify a table.
57 * We "abuse" it here to actually check if access is allowed to sys_file_metadata.
58 *
59 *
60 * @param int &$accessAllowed Whether the user has access to modify a table
61 * @param string $table The name of the table to be modified
62 * @param DataHandler $parent The calling parent object
63 * @throws \UnexpectedValueException
64 */
65 public function checkModifyAccessList(&$accessAllowed, $table, DataHandler $parent)
66 {
67 if ($table === 'sys_file_metadata') {
68 if (isset($parent->cmdmap[$table]) && is_array($parent->cmdmap[$table])) {
69 foreach ($parent->cmdmap[$table] as $id => $command) {
70 if (empty($id) || !MathUtility::canBeInterpretedAsInteger($id)) {
71 throw new \UnexpectedValueException(
72 'Integer expected for data manipulation command.
73 This can only happen in the case of an attack attempt or when something went horribly wrong.
74 To not compromise security, we exit here.',
75 1399982816
76 );
77 }
78
79 $fileMetadataRecord = BackendUtility::getRecord('sys_file_metadata', $id);
80 $accessAllowed = $this->checkFileWriteAccessForFileMetaData($fileMetadataRecord);
81 if (!$accessAllowed) {
82 // If for any item in the array, access is not allowed, we deny the whole operation
83 break;
84 }
85 }
86 }
87
88 if (isset($parent->datamap[$table]) && is_array($parent->datamap[$table])) {
89 foreach ($parent->datamap[$table] as $id => $data) {
90 $recordAccessAllowed = false;
91
92 if (strpos($id, 'NEW') === false) {
93 $fileMetadataRecord = BackendUtility::getRecord('sys_file_metadata', $id);
94 if ($fileMetadataRecord !== null) {
95 if ($parent->isImporting && empty($fileMetadataRecord['file'])) {
96 // When importing the record was added with an empty file relation as first step
97 $recordAccessAllowed = true;
98 } else {
99 $recordAccessAllowed = $this->checkFileWriteAccessForFileMetaData($fileMetadataRecord);
100 }
101 }
102 } else {
103 // For new records record access is allowed
104 $recordAccessAllowed = true;
105 }
106
107 if (isset($data['file'])) {
108 if ($parent->isImporting && empty($data['file'])) {
109 // When importing the record will be created with an empty file relation as first step
110 $dataAccessAllowed = true;
111 } elseif (empty($data['file'])) {
112 $dataAccessAllowed = false;
113 } else {
114 $dataAccessAllowed = $this->checkFileWriteAccessForFileMetaData($data);
115 }
116 } else {
117 $dataAccessAllowed = true;
118 }
119
120 if (!$recordAccessAllowed || !$dataAccessAllowed) {
121 // If for any item in the array, access is not allowed, we deny the whole operation
122 $accessAllowed = false;
123 break;
124 }
125 }
126 }
127 }
128 }
129
130 /**
131 * Deny access to the edit form. This is not mandatory, but better to show this right away that access is denied.
132 *
133 * @param array $parameters
134 * @return bool
135 */
136 public function isAllowedToShowEditForm(array $parameters)
137 {
138 $table = $parameters['table'];
139 $uid = $parameters['uid'];
140 $cmd = $parameters['cmd'];
141 $accessAllowed = $parameters['hasAccess'];
142
143 if ($accessAllowed && $table === 'sys_file_metadata' && $cmd === 'edit') {
144 $fileMetadataRecord = BackendUtility::getRecord('sys_file_metadata', $uid);
145 $accessAllowed = $this->checkFileWriteAccessForFileMetaData($fileMetadataRecord);
146 }
147 return $accessAllowed;
148 }
149
150 /**
151 * Checks write access to the file belonging to a metadata entry
152 *
153 * @param array $fileMetadataRecord
154 * @return bool
155 */
156 protected function checkFileWriteAccessForFileMetaData($fileMetadataRecord)
157 {
158 $accessAllowed = false;
159 if (is_array($fileMetadataRecord) && !empty($fileMetadataRecord['file'])) {
160 $file = $fileMetadataRecord['file'];
161 // The file relation could be written as sys_file_[uid], strip this off before checking the rights
162 if (strpos($file, 'sys_file_') !== false) {
163 $file = substr($file, strlen('sys_file_'));
164 }
165 $fileObject = ResourceFactory::getInstance()->getFileObject((int)$file);
166 $accessAllowed = $fileObject->checkActionPermission('write');
167 }
168 return $accessAllowed;
169 }
170 }