These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Nextcloud - NextNote |
||
4 | * |
||
5 | * @copyright Copyright (c) 2015, Ben Curtis <[email protected]> |
||
6 | * @copyright Copyright (c) 2017, Sander Brand ([email protected]) |
||
7 | * @license GNU AGPL version 3 or any later version |
||
8 | * |
||
9 | * This program is free software: you can redistribute it and/or modify |
||
10 | * it under the terms of the GNU Affero General Public License as |
||
11 | * published by the Free Software Foundation, either version 3 of the |
||
12 | * License, or (at your option) any later version. |
||
13 | * |
||
14 | * This program is distributed in the hope that it will be useful, |
||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | * GNU Affero General Public License for more details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU Affero General Public License |
||
20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
21 | * |
||
22 | */ |
||
23 | |||
24 | namespace OCA\NextNote\Fixtures; |
||
25 | |||
26 | use OC\Share\Helper; |
||
27 | use OC\Share\Share; |
||
28 | use OCA\NextNote\Utility\Utils; |
||
29 | |||
30 | class ShareFix extends Share { |
||
31 | |||
32 | private static function log($level, $message, $context) { |
||
33 | \OC::$server->getLogger()->log($level, $message, $context); |
||
34 | } |
||
35 | |||
36 | /** |
||
37 | * Set the permissions of an item for a specific user or group |
||
38 | * |
||
39 | * @param string $itemType |
||
40 | * @param string $itemSource |
||
41 | * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK |
||
42 | * @param string $shareWith User or group the item is being shared with |
||
43 | * @param int $permissions CRUDS permissions |
||
44 | * @return boolean true on success or false on failure |
||
45 | * @throws \Exception when trying to grant more permissions then the user has himself |
||
46 | */ |
||
47 | public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) { |
||
48 | $l = \OC::$server->getL10N('lib'); |
||
49 | $connection = \OC::$server->getDatabaseConnection(); |
||
50 | |||
51 | $intArrayToLiteralArray = function ($intArray, $eb) { |
||
52 | return array_map(function ($int) use ($eb) { |
||
53 | return $eb->literal((int)$int, 'integer'); |
||
54 | }, $intArray); |
||
55 | }; |
||
56 | $sanitizeItem = function ($item) { |
||
57 | $item['id'] = (int)$item['id']; |
||
58 | $item['premissions'] = (int)$item['permissions']; |
||
59 | return $item; |
||
60 | }; |
||
61 | |||
62 | if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith, |
||
63 | \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) { |
||
64 | // Check if this item is a reshare and verify that the permissions |
||
65 | // granted don't exceed the parent shared item |
||
66 | if (isset($rootItem['parent'])) { |
||
67 | $qb = $connection->getQueryBuilder(); |
||
68 | $qb->select('permissions') |
||
69 | ->from('share') |
||
70 | ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
||
71 | ->setParameter(':id', $rootItem['parent']); |
||
72 | $dbresult = $qb->execute(); |
||
73 | |||
74 | $result = $dbresult->fetch(); |
||
75 | $dbresult->closeCursor(); |
||
76 | if (~(int)$result['permissions'] & $permissions) { |
||
77 | $message = 'Setting permissions for %s failed,' |
||
78 | . ' because the permissions exceed permissions granted to %s'; |
||
79 | $message_t = $l->t('Setting permissions for %s failed, because the permissions exceed permissions granted to %s', array($itemSource, \OC_User::getUser())); |
||
80 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSource, \OC_User::getUser()), \OCP\Util::DEBUG); |
||
81 | throw new \Exception($message_t); |
||
82 | } |
||
83 | } |
||
84 | $qb = $connection->getQueryBuilder(); |
||
85 | $qb->update('share') |
||
86 | ->set('permissions', $qb->createParameter('permissions')) |
||
87 | ->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
||
88 | ->setParameter(':id', $rootItem['id']) |
||
89 | ->setParameter(':permissions', $permissions); |
||
90 | $qb->execute(); |
||
91 | if ($itemType === 'file' || $itemType === 'folder') { |
||
92 | \OC_Hook::emit('NextNote\Fixtures\ShareFix', 'post_update_permissions', array( |
||
93 | 'itemType' => $itemType, |
||
94 | 'itemSource' => $itemSource, |
||
95 | 'shareType' => $shareType, |
||
96 | 'shareWith' => $shareWith, |
||
97 | 'uidOwner' => \OC_User::getUser(), |
||
98 | 'permissions' => $permissions, |
||
99 | 'path' => $rootItem['path'], |
||
100 | 'share' => $rootItem |
||
101 | )); |
||
102 | } |
||
103 | |||
104 | // Share id's to update with the new permissions |
||
105 | $ids = []; |
||
106 | $items = []; |
||
107 | |||
108 | // Check if permissions were removed |
||
109 | if ((int)$rootItem['permissions'] & ~$permissions) { |
||
110 | // If share permission is removed all reshares must be deleted |
||
111 | if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) { |
||
112 | // delete all shares, keep parent and group children |
||
113 | Helper::delete($rootItem['id'], true, null, null, true); |
||
114 | } |
||
115 | |||
116 | // Remove permission from all children |
||
117 | $parents = [$rootItem['id']]; |
||
118 | while (!empty($parents)) { |
||
119 | $parents = $intArrayToLiteralArray($parents, $qb->expr()); |
||
120 | $qb = $connection->getQueryBuilder(); |
||
121 | $qb->select('id', 'permissions', 'item_type') |
||
122 | ->from('share') |
||
123 | ->where($qb->expr()->in('parent', $parents)); |
||
124 | $result = $qb->execute(); |
||
125 | // Reset parents array, only go through loop again if |
||
126 | // items are found that need permissions removed |
||
127 | $parents = []; |
||
128 | while ($item = $result->fetch()) { |
||
129 | $item = $sanitizeItem($item); |
||
130 | |||
131 | $items[] = $item; |
||
132 | // Check if permissions need to be removed |
||
133 | if ($item['permissions'] & ~$permissions) { |
||
134 | // Add to list of items that need permissions removed |
||
135 | $ids[] = $item['id']; |
||
136 | $parents[] = $item['id']; |
||
137 | } |
||
138 | } |
||
139 | $result->closeCursor(); |
||
140 | } |
||
141 | |||
142 | // Remove the permissions for all reshares of this item |
||
143 | if (!empty($ids)) { |
||
144 | $ids = "'" . implode("','", $ids) . "'"; |
||
145 | // TODO this should be done with Doctrine platform objects |
||
146 | if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') { |
||
147 | $andOp = 'BITAND(`permissions`, ?)'; |
||
148 | } else { |
||
149 | $andOp = '`permissions` & ?'; |
||
150 | } |
||
151 | $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ' . $andOp |
||
152 | . ' WHERE `id` IN (' . $ids . ')'); |
||
153 | $query->execute(array($permissions)); |
||
154 | } |
||
155 | |||
156 | } |
||
157 | |||
158 | /* |
||
159 | * Permissions were added |
||
160 | * Update all USERGROUP shares. (So group shares where the user moved their mountpoint). |
||
161 | */ |
||
162 | if ($permissions & ~(int)$rootItem['permissions']) { |
||
163 | $qb = $connection->getQueryBuilder(); |
||
164 | $qb->select('id', 'permissions', 'item_type') |
||
165 | ->from('share') |
||
166 | ->where($qb->expr()->eq('parent', $qb->createParameter('parent'))) |
||
167 | ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type'))) |
||
168 | ->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted'))) |
||
169 | ->setParameter(':parent', (int)$rootItem['id']) |
||
170 | ->setParameter(':share_type', 2) |
||
171 | ->setParameter(':shareDeleted', 0); |
||
172 | $result = $qb->execute(); |
||
173 | |||
174 | $ids = []; |
||
175 | while ($item = $result->fetch()) { |
||
176 | $item = $sanitizeItem($item); |
||
177 | $items[] = $item; |
||
178 | $ids[] = $item['id']; |
||
179 | } |
||
180 | $result->closeCursor(); |
||
181 | |||
182 | // Add permssions for all USERGROUP shares of this item |
||
183 | if (!empty($ids)) { |
||
184 | $ids = $intArrayToLiteralArray($ids, $qb->expr()); |
||
185 | |||
186 | $qb = $connection->getQueryBuilder(); |
||
187 | $qb->update('share') |
||
188 | ->set('permissions', $qb->createParameter('permissions')) |
||
189 | ->where($qb->expr()->in('id', $ids)) |
||
190 | ->setParameter(':permissions', $permissions); |
||
191 | $qb->execute(); |
||
192 | } |
||
193 | } |
||
194 | |||
195 | foreach ($items as $item) { |
||
196 | \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]); |
||
197 | } |
||
198 | |||
199 | return true; |
||
200 | } |
||
201 | $message = 'Setting permissions for %s failed, because the item was not found'; |
||
202 | $message_t = $l->t('Setting permissions for %s failed, because the item was not found', array($itemSource)); |
||
203 | |||
204 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSource), \OCP\Util::DEBUG); |
||
205 | throw new \Exception($message_t); |
||
206 | } |
||
207 | |||
208 | /** |
||
209 | * Get the item of item type shared with the current user |
||
210 | * |
||
211 | * @param string $itemType |
||
212 | * @param string $itemTarget |
||
213 | * @param int $format (optional) Format type must be defined by the backend |
||
214 | * @param mixed $parameters (optional) |
||
215 | * @param boolean $includeCollections (optional) |
||
216 | * @return mixed Return depends on format |
||
217 | */ |
||
218 | public static function getItemSharedWith($itemType, $itemTarget, $format = parent::FORMAT_NONE, |
||
219 | $parameters = null, $includeCollections = false) { |
||
220 | |||
221 | return self::getItems($itemType, $itemTarget, parent::$shareTypeUserAndGroups, \OC_User::getUser(), null, self::FORMAT_NONE, |
||
222 | $parameters, 1, $includeCollections); |
||
223 | } |
||
224 | |||
225 | |||
226 | /** |
||
227 | * Get all users an item is shared with |
||
228 | * |
||
229 | * @param string $itemType |
||
230 | * @param string $itemSource |
||
231 | * @return array Return array of users |
||
232 | */ |
||
233 | public static function getUsersItemShared($itemType, $itemSource) { |
||
234 | |||
235 | $users = array(); |
||
236 | $queryArgs = [ |
||
237 | $itemType, |
||
238 | $itemSource |
||
239 | ]; |
||
240 | $where = '`item_type` = ?'; |
||
241 | $where .= ' AND `item_source`= ?'; |
||
242 | $q = 'SELECT * FROM `*PREFIX*share` WHERE ' . $where; |
||
243 | $query = \OC_DB::prepare($q); |
||
244 | |||
245 | $result = $query->execute($queryArgs); |
||
246 | while ($row = $result->fetchRow()) { |
||
247 | if ($row['share_type'] == self::SHARE_TYPE_USER) { |
||
248 | $u = Utils::getUserInfo($row['share_with']); |
||
249 | $users[] = $u['display_name']; |
||
250 | } |
||
251 | if ($row['share_type'] == self::SHARE_TYPE_GROUP) { |
||
252 | $users[] = $row['share_with']; |
||
253 | } |
||
254 | } |
||
255 | |||
256 | return $users; |
||
257 | } |
||
258 | |||
259 | |||
260 | /** |
||
261 | * Share an item with a user, group, or via private link |
||
262 | * |
||
263 | * @param string $itemType |
||
264 | * @param string $itemSource |
||
265 | * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK |
||
266 | * @param string $shareWith User or group the item is being shared with |
||
267 | * @param int $permissions CRUDS |
||
268 | * @param string $itemSourceName |
||
269 | * @param \DateTime|null $expirationDate |
||
270 | * @param bool|null $passwordChanged |
||
271 | * @return boolean|string Returns true on success or false on failure, Returns token on success for links |
||
272 | * @throws \OC\HintException when the share type is remote and the shareWith is invalid |
||
273 | * @throws \Exception |
||
274 | * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0 |
||
275 | */ |
||
276 | public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) { |
||
277 | |||
278 | $backend = self::getBackend($itemType); |
||
279 | $l = \OC::$server->getL10N('lib'); |
||
280 | |||
281 | View Code Duplication | if ($backend->isShareTypeAllowed($shareType) === false) { |
|
282 | $message = 'Sharing %s failed, because the backend does not allow shares from type %i'; |
||
283 | $message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType)); |
||
284 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG); |
||
285 | throw new \Exception($message_t); |
||
286 | } |
||
287 | |||
288 | $uidOwner = \OC_User::getUser(); |
||
289 | $shareWithinGroupOnly = self::shareWithGroupMembersOnly(); |
||
290 | |||
291 | if (is_null($itemSourceName)) { |
||
292 | $itemSourceName = $itemSource; |
||
293 | } |
||
294 | $itemName = $itemSourceName; |
||
295 | |||
296 | //Validate expirationDate |
||
297 | if ($expirationDate !== null) { |
||
298 | try { |
||
299 | /* |
||
300 | * Reuse the validateExpireDate. |
||
301 | * We have to pass time() since the second arg is the time |
||
302 | * the file was shared, since it is not shared yet we just use |
||
303 | * the current time. |
||
304 | */ |
||
305 | $expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource); |
||
306 | } catch (\Exception $e) { |
||
307 | throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404); |
||
308 | } |
||
309 | } |
||
310 | |||
311 | // Verify share type and sharing conditions are met |
||
312 | if ($shareType === self::SHARE_TYPE_USER) { |
||
313 | if ($shareWith == $uidOwner) { |
||
314 | $message = 'Sharing %s failed, because you can not share with yourself'; |
||
315 | $message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]); |
||
316 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName), \OCP\Util::DEBUG); |
||
317 | throw new \Exception($message_t); |
||
318 | } |
||
319 | View Code Duplication | if (!\OC::$server->getUserManager()->userExists($shareWith)) { |
|
320 | $message = 'Sharing %s failed, because the user %s does not exist'; |
||
321 | $message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith)); |
||
322 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); |
||
323 | throw new \Exception($message_t); |
||
324 | } |
||
325 | if ($shareWithinGroupOnly) { |
||
326 | $userManager = \OC::$server->getUserManager(); |
||
327 | $groupManager = \OC::$server->getGroupManager(); |
||
328 | $userOwner = $userManager->get($uidOwner); |
||
329 | $userShareWith = $userManager->get($shareWith); |
||
330 | $groupsOwner = []; |
||
331 | $groupsShareWith = []; |
||
332 | if ($userOwner) { |
||
333 | $groupsOwner = $groupManager->getUserGroupIds($userOwner); |
||
334 | } |
||
335 | if ($userShareWith) { |
||
336 | $groupsShareWith = $groupManager->getUserGroupIds($userShareWith); |
||
337 | } |
||
338 | $inGroup = array_intersect($groupsOwner, $groupsShareWith); |
||
339 | View Code Duplication | if (empty($inGroup)) { |
|
340 | $message = 'Sharing %s failed, because the user ' |
||
341 | . '%s is not a member of any groups that %s is a member of'; |
||
342 | $message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner)); |
||
343 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG); |
||
344 | throw new \Exception($message_t); |
||
345 | } |
||
346 | } |
||
347 | // Check if the item source is already shared with the user, either from the same owner or a different user |
||
348 | View Code Duplication | if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, |
|
349 | $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { |
||
350 | // Only allow the same share to occur again if it is the same |
||
351 | // owner and is not a user share, this use case is for increasing |
||
352 | // permissions for a specific user |
||
353 | if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { |
||
354 | $message = 'Sharing %s failed, because this item is already shared with %s'; |
||
355 | $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith)); |
||
356 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); |
||
357 | throw new \Exception($message_t); |
||
358 | } |
||
359 | } |
||
360 | View Code Duplication | if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER, |
|
361 | $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { |
||
362 | // Only allow the same share to occur again if it is the same |
||
363 | // owner and is not a user share, this use case is for increasing |
||
364 | // permissions for a specific user |
||
365 | if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { |
||
366 | $message = 'Sharing %s failed, because this item is already shared with user %s'; |
||
367 | $message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith)); |
||
368 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR); |
||
369 | throw new \Exception($message_t); |
||
370 | } |
||
371 | } |
||
372 | } else if ($shareType === self::SHARE_TYPE_GROUP) { |
||
373 | View Code Duplication | if (!\OC::$server->getGroupManager()->groupExists($shareWith)) { |
|
374 | $message = 'Sharing %s failed, because the group %s does not exist'; |
||
375 | $message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith)); |
||
376 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); |
||
377 | throw new \Exception($message_t); |
||
378 | } |
||
379 | if ($shareWithinGroupOnly) { |
||
380 | $group = \OC::$server->getGroupManager()->get($shareWith); |
||
381 | $user = \OC::$server->getUserManager()->get($uidOwner); |
||
382 | if (!$group || !$user || !$group->inGroup($user)) { |
||
383 | $message = 'Sharing %s failed, because ' |
||
384 | . '%s is not a member of the group %s'; |
||
385 | $message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith)); |
||
386 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG); |
||
387 | throw new \Exception($message_t); |
||
388 | } |
||
389 | } |
||
390 | // Check if the item source is already shared with the group, either from the same owner or a different user |
||
391 | // The check for each user in the group is done inside the put() function |
||
392 | if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, |
||
393 | null, self::FORMAT_NONE, null, 1, true, true)) { |
||
394 | |||
395 | if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) { |
||
396 | $message = 'Sharing %s failed, because this item is already shared with %s'; |
||
397 | $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith)); |
||
398 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); |
||
399 | throw new \Exception($message_t); |
||
400 | } |
||
401 | } |
||
402 | // Convert share with into an array with the keys group and users |
||
403 | $group = $shareWith; |
||
404 | $shareWith = array(); |
||
405 | $shareWith['group'] = $group; |
||
406 | |||
407 | |||
408 | $groupObject = \OC::$server->getGroupManager()->get($group); |
||
409 | $userIds = []; |
||
410 | if ($groupObject) { |
||
411 | $users = $groupObject->searchUsers(''); |
||
412 | foreach ($users as $user) { |
||
413 | $userIds[] = $user->getUID(); |
||
414 | } |
||
415 | } |
||
416 | |||
417 | |||
418 | $shareWith['users'] = array_diff($userIds, array($uidOwner)); |
||
419 | } else { |
||
420 | // Future share types need to include their own conditions |
||
421 | $message = 'Share type %s is not valid for %s'; |
||
422 | $message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource)); |
||
423 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG); |
||
424 | throw new \Exception($message_t); |
||
425 | } |
||
426 | |||
427 | // Put the item into the database |
||
428 | $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate); |
||
429 | |||
430 | return $result ? true : false; |
||
431 | } |
||
432 | |||
433 | /** |
||
434 | * Put shared item into the database |
||
435 | * |
||
436 | * @param string $itemType Item type |
||
437 | * @param string $itemSource Item source |
||
438 | * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK |
||
439 | * @param string $shareWith User or group the item is being shared with |
||
440 | * @param string $uidOwner User that is the owner of shared item |
||
441 | * @param int $permissions CRUDS permissions |
||
442 | * @param boolean|array $parentFolder Parent folder target (optional) |
||
443 | * @param string $token (optional) |
||
444 | * @param string $itemSourceName name of the source item (optional) |
||
445 | * @param \DateTime $expirationDate (optional) |
||
446 | * @throws \Exception |
||
447 | * @return mixed id of the new share or false |
||
448 | */ |
||
449 | private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, |
||
450 | $permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) { |
||
451 | |||
452 | $queriesToExecute = array(); |
||
453 | $suggestedItemTarget = null; |
||
454 | $groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = ''; |
||
455 | $groupItemTarget = $itemTarget = $fileSource = $parent = 0; |
||
456 | |||
457 | $result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate); |
||
458 | if (!empty($result)) { |
||
459 | $parent = $result['parent']; |
||
460 | $itemSource = $result['itemSource']; |
||
461 | $fileSource = $result['fileSource']; |
||
462 | $suggestedItemTarget = $result['suggestedItemTarget']; |
||
463 | $suggestedFileTarget = $result['suggestedFileTarget']; |
||
464 | $filePath = $result['filePath']; |
||
465 | } |
||
466 | |||
467 | $isGroupShare = false; |
||
468 | if ($shareType == self::SHARE_TYPE_GROUP) { |
||
469 | $isGroupShare = true; |
||
470 | if (isset($shareWith['users'])) { |
||
471 | $users = $shareWith['users']; |
||
472 | } else { |
||
473 | $group = \OC::$server->getGroupManager()->get($shareWith['group']); |
||
474 | if ($group) { |
||
475 | $users = $group->searchUsers(''); |
||
476 | $userIds = []; |
||
477 | foreach ($users as $user) { |
||
478 | $userIds[] = $user->getUID(); |
||
479 | } |
||
480 | $users = $userIds; |
||
481 | } else { |
||
482 | $users = []; |
||
483 | } |
||
484 | } |
||
485 | // remove current user from list |
||
486 | if (in_array(\OC::$server->getUserSession()->getUser()->getUID(), $users)) { |
||
487 | unset($users[array_search(\OC::$server->getUserSession()->getUser()->getUID(), $users)]); |
||
488 | } |
||
489 | $groupItemTarget = Helper::generateTarget($itemType, $itemSource, |
||
490 | $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget); |
||
491 | $groupFileTarget = Helper::generateTarget($itemType, $itemSource, |
||
492 | $shareType, $shareWith['group'], $uidOwner, $filePath); |
||
493 | |||
494 | // add group share to table and remember the id as parent |
||
495 | $queriesToExecute['groupShare'] = array( |
||
496 | 'itemType' => $itemType, |
||
497 | 'itemSource' => $itemSource, |
||
498 | 'itemTarget' => $groupItemTarget, |
||
499 | 'shareType' => $shareType, |
||
500 | 'shareWith' => $shareWith['group'], |
||
501 | 'uidOwner' => $uidOwner, |
||
502 | 'permissions' => $permissions, |
||
503 | 'shareTime' => time(), |
||
504 | 'fileSource' => $fileSource, |
||
505 | 'fileTarget' => $groupFileTarget, |
||
506 | 'token' => $token, |
||
507 | 'parent' => $parent, |
||
508 | 'expiration' => $expirationDate, |
||
509 | ); |
||
510 | |||
511 | } else { |
||
512 | $users = array($shareWith); |
||
513 | $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, |
||
514 | $suggestedItemTarget); |
||
515 | } |
||
516 | |||
517 | $run = true; |
||
518 | $error = ''; |
||
519 | $preHookData = array( |
||
520 | 'itemType' => $itemType, |
||
521 | 'itemSource' => $itemSource, |
||
522 | 'shareType' => $shareType, |
||
523 | 'uidOwner' => $uidOwner, |
||
524 | 'permissions' => $permissions, |
||
525 | 'fileSource' => $fileSource, |
||
526 | 'expiration' => $expirationDate, |
||
527 | 'token' => $token, |
||
528 | 'run' => &$run, |
||
529 | 'error' => &$error |
||
530 | ); |
||
531 | |||
532 | $preHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget; |
||
533 | $preHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith; |
||
534 | |||
535 | \OC_Hook::emit(\OCP\Share::class, 'pre_shared', $preHookData); |
||
536 | |||
537 | if ($run === false) { |
||
538 | throw new \Exception($error); |
||
539 | } |
||
540 | |||
541 | foreach ($users as $user) { |
||
542 | $sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource; |
||
543 | $sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user); |
||
544 | |||
545 | $userShareType = $isGroupShare ? self::$shareTypeGroupUserUnique : $shareType; |
||
546 | |||
547 | if ($sourceExists && $sourceExists['item_source'] === $itemSource) { |
||
548 | $fileTarget = $sourceExists['file_target']; |
||
549 | $itemTarget = $sourceExists['item_target']; |
||
550 | |||
551 | // for group shares we don't need a additional entry if the target is the same |
||
552 | if ($isGroupShare && $groupItemTarget === $itemTarget) { |
||
553 | continue; |
||
554 | } |
||
555 | |||
556 | } elseif (!$sourceExists && !$isGroupShare) { |
||
557 | |||
558 | $itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user, |
||
559 | $uidOwner, $suggestedItemTarget, $parent); |
||
560 | if (isset($fileSource)) { |
||
561 | if ($parentFolder) { |
||
562 | if ($parentFolder === true) { |
||
563 | $fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user, |
||
564 | $uidOwner, $suggestedFileTarget, $parent); |
||
565 | if ($fileTarget != $groupFileTarget) { |
||
566 | $parentFolders[$user]['folder'] = $fileTarget; |
||
0 ignored issues
–
show
|
|||
567 | } |
||
568 | } else if (isset($parentFolder[$user])) { |
||
569 | $fileTarget = $parentFolder[$user]['folder'] . $itemSource; |
||
570 | $parent = $parentFolder[$user]['id']; |
||
571 | } |
||
572 | } else { |
||
573 | $fileTarget = Helper::generateTarget('file', $filePath, $userShareType, |
||
574 | $user, $uidOwner, $suggestedFileTarget, $parent); |
||
575 | } |
||
576 | } else { |
||
577 | $fileTarget = null; |
||
578 | } |
||
579 | |||
580 | } else { |
||
581 | |||
582 | // group share which doesn't exists until now, check if we need a unique target for this user |
||
583 | |||
584 | $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user, |
||
585 | $uidOwner, $suggestedItemTarget, $parent); |
||
586 | |||
587 | // do we also need a file target |
||
588 | if (isset($fileSource)) { |
||
589 | $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user, |
||
590 | $uidOwner, $suggestedFileTarget, $parent); |
||
591 | } else { |
||
592 | $fileTarget = null; |
||
593 | } |
||
594 | |||
595 | if (($itemTarget === $groupItemTarget) && |
||
596 | (!isset($fileSource) || $fileTarget === $groupFileTarget)) { |
||
597 | continue; |
||
598 | } |
||
599 | } |
||
600 | |||
601 | $queriesToExecute[] = array( |
||
602 | 'itemType' => $itemType, |
||
603 | 'itemSource' => $itemSource, |
||
604 | 'itemTarget' => $itemTarget, |
||
605 | 'shareType' => $userShareType, |
||
606 | 'shareWith' => $user, |
||
607 | 'uidOwner' => $uidOwner, |
||
608 | 'permissions' => $permissions, |
||
609 | 'shareTime' => time(), |
||
610 | 'fileSource' => $fileSource, |
||
611 | 'fileTarget' => $fileTarget, |
||
612 | 'token' => $token, |
||
613 | 'parent' => $parent, |
||
614 | 'expiration' => $expirationDate, |
||
615 | ); |
||
616 | |||
617 | } |
||
618 | |||
619 | $id = false; |
||
620 | if ($isGroupShare) { |
||
621 | $id = self::insertShare($queriesToExecute['groupShare']); |
||
622 | // Save this id, any extra rows for this group share will need to reference it |
||
623 | $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share'); |
||
624 | unset($queriesToExecute['groupShare']); |
||
625 | } |
||
626 | |||
627 | foreach ($queriesToExecute as $shareQuery) { |
||
628 | $shareQuery['parent'] = $parent; |
||
629 | $id = self::insertShare($shareQuery); |
||
630 | } |
||
631 | |||
632 | $postHookData = array( |
||
633 | 'itemType' => $itemType, |
||
634 | 'itemSource' => $itemSource, |
||
635 | 'parent' => $parent, |
||
636 | 'shareType' => $shareType, |
||
637 | 'uidOwner' => $uidOwner, |
||
638 | 'permissions' => $permissions, |
||
639 | 'fileSource' => $fileSource, |
||
640 | 'id' => $parent, |
||
641 | 'token' => $token, |
||
642 | 'expirationDate' => $expirationDate, |
||
643 | ); |
||
644 | |||
645 | $postHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith; |
||
646 | $postHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget; |
||
647 | $postHookData['fileTarget'] = $isGroupShare ? $groupFileTarget : $fileTarget; |
||
648 | |||
649 | \OC_Hook::emit(\OCP\Share::class, 'post_shared', $postHookData); |
||
650 | |||
651 | |||
652 | return $id ? $id : false; |
||
653 | } |
||
654 | |||
655 | /** |
||
656 | * @param string $itemType |
||
657 | * @param string $itemSource |
||
658 | * @param int $shareType |
||
659 | * @param string $shareWith |
||
660 | * @param string $uidOwner |
||
661 | * @param int $permissions |
||
662 | * @param string|null $itemSourceName |
||
663 | * @param null|\DateTime $expirationDate |
||
664 | */ |
||
665 | private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) { |
||
666 | $backend = self::getBackend($itemType); |
||
667 | |||
668 | $l = \OC::$server->getL10N('lib'); |
||
669 | $result = array(); |
||
670 | |||
671 | $column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source'; |
||
672 | |||
673 | $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true); |
||
674 | if ($checkReshare) { |
||
675 | // Check if attempting to share back to owner |
||
676 | if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) { |
||
677 | $message = 'Sharing %s failed, because the user %s is the original sharer'; |
||
678 | $message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]); |
||
679 | |||
680 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); |
||
681 | throw new \Exception($message_t); |
||
682 | } |
||
683 | } |
||
684 | |||
685 | if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) { |
||
686 | // Check if share permissions is granted |
||
687 | if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) { |
||
688 | if (~(int)$checkReshare['permissions'] & $permissions) { |
||
689 | $message = 'Sharing %s failed, because the permissions exceed permissions granted to %s'; |
||
690 | $message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner)); |
||
691 | |||
692 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG); |
||
693 | throw new \Exception($message_t); |
||
694 | } else { |
||
695 | // TODO Don't check if inside folder |
||
696 | $result['parent'] = $checkReshare['id']; |
||
697 | |||
698 | $result['expirationDate'] = $expirationDate; |
||
699 | // $checkReshare['expiration'] could be null and then is always less than any value |
||
700 | if (isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) { |
||
701 | $result['expirationDate'] = $checkReshare['expiration']; |
||
702 | } |
||
703 | |||
704 | // only suggest the same name as new target if it is a reshare of the |
||
705 | // same file/folder and not the reshare of a child |
||
706 | if ($checkReshare[$column] === $itemSource) { |
||
707 | $result['filePath'] = $checkReshare['file_target']; |
||
708 | $result['itemSource'] = $checkReshare['item_source']; |
||
709 | $result['fileSource'] = $checkReshare['file_source']; |
||
710 | $result['suggestedItemTarget'] = $checkReshare['item_target']; |
||
711 | $result['suggestedFileTarget'] = $checkReshare['file_target']; |
||
712 | } else { |
||
713 | $result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null; |
||
714 | $result['suggestedItemTarget'] = null; |
||
715 | $result['suggestedFileTarget'] = null; |
||
716 | $result['itemSource'] = $itemSource; |
||
717 | $result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null; |
||
718 | } |
||
719 | } |
||
720 | View Code Duplication | } else { |
|
721 | $message = 'Sharing %s failed, because resharing is not allowed'; |
||
722 | $message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName)); |
||
723 | |||
724 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSourceName), \OCP\Util::DEBUG); |
||
725 | throw new \Exception($message_t); |
||
726 | } |
||
727 | } else { |
||
728 | $result['parent'] = null; |
||
729 | $result['suggestedItemTarget'] = null; |
||
730 | $result['suggestedFileTarget'] = null; |
||
731 | $result['itemSource'] = $itemSource; |
||
732 | $result['expirationDate'] = $expirationDate; |
||
733 | View Code Duplication | if (!$backend->isValidSource($itemSource, $uidOwner)) { |
|
734 | $message = 'Sharing %s failed, because the sharing backend for ' |
||
735 | . '%s could not find its source'; |
||
736 | $message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType)); |
||
737 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG); |
||
738 | throw new \Exception($message_t); |
||
739 | } |
||
740 | if ($backend instanceof \OCP\Share_Backend_File_Dependent) { |
||
741 | $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner); |
||
742 | if ($itemType == 'file' || $itemType == 'folder') { |
||
743 | $result['fileSource'] = $itemSource; |
||
744 | } else { |
||
745 | $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']); |
||
746 | $result['fileSource'] = $meta['fileid']; |
||
747 | } |
||
748 | if ($result['fileSource'] == -1) { |
||
749 | $message = 'Sharing %s failed, because the file could not be found in the file cache'; |
||
750 | $message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource)); |
||
751 | |||
752 | self::log('NextNote\Fixtures\ShareFix', sprintf($message, $itemSource), \OCP\Util::DEBUG); |
||
753 | throw new \Exception($message_t); |
||
754 | } |
||
755 | } else { |
||
756 | $result['filePath'] = null; |
||
757 | $result['fileSource'] = null; |
||
758 | } |
||
759 | } |
||
760 | |||
761 | return $result; |
||
762 | } |
||
763 | |||
764 | /** |
||
765 | * |
||
766 | * @param array $shareData |
||
767 | * @return mixed false in case of a failure or the id of the new share |
||
768 | */ |
||
769 | private static function insertShare(array $shareData) { |
||
770 | |||
771 | $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (' |
||
772 | . ' `item_type`, `item_source`, `item_target`, `share_type`,' |
||
773 | . ' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,' |
||
774 | . ' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)'); |
||
775 | $query->bindValue(1, $shareData['itemType']); |
||
776 | $query->bindValue(2, $shareData['itemSource']); |
||
777 | $query->bindValue(3, $shareData['itemTarget']); |
||
778 | $query->bindValue(4, $shareData['shareType']); |
||
779 | $query->bindValue(5, $shareData['shareWith']); |
||
780 | $query->bindValue(6, $shareData['uidOwner']); |
||
781 | $query->bindValue(7, $shareData['permissions']); |
||
782 | $query->bindValue(8, $shareData['shareTime']); |
||
783 | $query->bindValue(9, $shareData['fileSource']); |
||
784 | $query->bindValue(10, $shareData['fileTarget']); |
||
785 | $query->bindValue(11, $shareData['token']); |
||
786 | $query->bindValue(12, $shareData['parent']); |
||
787 | $query->bindValue(13, $shareData['expiration'], 'datetime'); |
||
788 | $result = $query->execute(); |
||
789 | |||
790 | $id = false; |
||
791 | if ($result) { |
||
792 | $id = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share'); |
||
793 | } |
||
794 | |||
795 | return $id; |
||
796 | |||
797 | } |
||
798 | |||
799 | /** |
||
800 | * validate expiration date if it meets all constraints |
||
801 | * |
||
802 | * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY" |
||
803 | * @param string $shareTime timestamp when the file was shared |
||
804 | * @param string $itemType |
||
805 | * @param string $itemSource |
||
806 | * @return \DateTime validated date |
||
807 | * @throws \Exception when the expire date is in the past or further in the future then the enforced date |
||
808 | */ |
||
809 | private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) { |
||
810 | $l = \OC::$server->getL10N('lib'); |
||
811 | $date = new \DateTime($expireDate); |
||
812 | $today = new \DateTime('now'); |
||
813 | |||
814 | // if the user doesn't provide a share time we need to get it from the database |
||
815 | // fall-back mode to keep API stable, because the $shareTime parameter was added later |
||
816 | $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced(); |
||
817 | if ($defaultExpireDateEnforced && $shareTime === null) { |
||
818 | $items = self::getItemShared($itemType, $itemSource); |
||
819 | $firstItem = reset($items); |
||
820 | $shareTime = (int)$firstItem['stime']; |
||
821 | } |
||
822 | |||
823 | if ($defaultExpireDateEnforced) { |
||
824 | // initialize max date with share time |
||
825 | $maxDate = new \DateTime(); |
||
826 | $maxDate->setTimestamp($shareTime); |
||
827 | $maxDays = \OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7'); |
||
828 | $maxDate->add(new \DateInterval('P' . $maxDays . 'D')); |
||
829 | if ($date > $maxDate) { |
||
830 | $warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared'; |
||
831 | $warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays)); |
||
832 | self::log('NextNote\Fixtures\ShareFix', $warning, \OCP\Util::WARN); |
||
833 | throw new \Exception($warning_t); |
||
834 | } |
||
835 | } |
||
836 | |||
837 | View Code Duplication | if ($date < $today) { |
|
838 | $message = 'Cannot set expiration date. Expiration date is in the past'; |
||
839 | $message_t = $l->t('Cannot set expiration date. Expiration date is in the past'); |
||
840 | self::log('NextNote\Fixtures\ShareFix', $message, \OCP\Util::WARN); |
||
841 | throw new \Exception($message_t); |
||
842 | } |
||
843 | |||
844 | return $date; |
||
845 | } |
||
846 | |||
847 | public static function getPermissions($itemType, $itemSource, $uid) { |
||
848 | $uid = \OC::$server->getUserSession()->getUser(); |
||
849 | $gm = \OC::$server->getGroupManager(); |
||
850 | |||
851 | $users = array(); |
||
852 | $queryArgs = [ |
||
853 | $itemType, |
||
854 | $itemSource, |
||
855 | $uid->getUID() |
||
856 | ]; |
||
857 | $where = '`item_type` = ?'; |
||
858 | $where .= ' AND `item_source`= ?'; |
||
859 | $where .= ' AND (`share_with` = ? AND `share_type`= 0 '; |
||
860 | |||
861 | $user_groups = $gm->getUserGroupIds($uid); |
||
862 | |||
863 | foreach ($user_groups as $group) { |
||
864 | $where .= ' OR (`share_with` = ? AND `share_type`=1)'; |
||
865 | $queryArgs[] = $group; |
||
866 | } |
||
867 | $where .= ')'; |
||
868 | |||
869 | $q = 'SELECT * FROM `*PREFIX*share` WHERE ' . $where; |
||
870 | |||
871 | |||
872 | $query = \OC_DB::prepare($q); |
||
873 | |||
874 | $result = $query->execute($queryArgs); |
||
875 | $permissions = 0; |
||
876 | while ($row = $result->fetchRow()) { |
||
877 | if ($row['permissions'] > $permissions) { |
||
878 | $permissions = $row['permissions']; |
||
879 | } |
||
880 | } |
||
881 | |||
882 | |||
883 | return $permissions; |
||
884 | } |
||
885 | |||
886 | } |
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.