Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/files_sharing/appinfo/routes.php5
-rw-r--r--apps/files_sharing/composer/composer/autoload_classmap.php1
-rw-r--r--apps/files_sharing/composer/composer/autoload_static.php1
-rw-r--r--apps/files_sharing/lib/Controller/ShareAPIController.php320
-rw-r--r--apps/files_sharing/lib/Exceptions/SharingRightsException.php40
5 files changed, 318 insertions, 49 deletions
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index ab5e829f86b..fa59cf936c9 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -54,6 +54,11 @@ return [
'verb' => 'GET',
],
[
+ 'name' => 'ShareAPI#getInheritedShares',
+ 'url' => '/api/v1/shares/inherited',
+ 'verb' => 'GET',
+ ],
+ [
'name' => 'ShareAPI#createShare',
'url' => '/api/v1/shares',
'verb' => 'POST',
diff --git a/apps/files_sharing/composer/composer/autoload_classmap.php b/apps/files_sharing/composer/composer/autoload_classmap.php
index af60a18718c..3a2b1159320 100644
--- a/apps/files_sharing/composer/composer/autoload_classmap.php
+++ b/apps/files_sharing/composer/composer/autoload_classmap.php
@@ -34,6 +34,7 @@ return array(
'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => $baseDir . '/../lib/DeleteOrphanedSharesJob.php',
'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => $baseDir . '/../lib/Exceptions/BrokenPath.php',
'OCA\\Files_Sharing\\Exceptions\\S2SException' => $baseDir . '/../lib/Exceptions/S2SException.php',
+ 'OCA\\Files_Sharing\\Exceptions\\SharingRightsException' => $baseDir . '/../lib/Exceptions/SharingRightsException.php',
'OCA\\Files_Sharing\\ExpireSharesJob' => $baseDir . '/../lib/ExpireSharesJob.php',
'OCA\\Files_Sharing\\External\\Cache' => $baseDir . '/../lib/External/Cache.php',
'OCA\\Files_Sharing\\External\\Manager' => $baseDir . '/../lib/External/Manager.php',
diff --git a/apps/files_sharing/composer/composer/autoload_static.php b/apps/files_sharing/composer/composer/autoload_static.php
index 67f8ce47f72..1c1322f6c3e 100644
--- a/apps/files_sharing/composer/composer/autoload_static.php
+++ b/apps/files_sharing/composer/composer/autoload_static.php
@@ -49,6 +49,7 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => __DIR__ . '/..' . '/../lib/DeleteOrphanedSharesJob.php',
'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => __DIR__ . '/..' . '/../lib/Exceptions/BrokenPath.php',
'OCA\\Files_Sharing\\Exceptions\\S2SException' => __DIR__ . '/..' . '/../lib/Exceptions/S2SException.php',
+ 'OCA\\Files_Sharing\\Exceptions\\SharingRightsException' => __DIR__ . '/..' . '/../lib/Exceptions/SharingRightsException.php',
'OCA\\Files_Sharing\\ExpireSharesJob' => __DIR__ . '/..' . '/../lib/ExpireSharesJob.php',
'OCA\\Files_Sharing\\External\\Cache' => __DIR__ . '/..' . '/../lib/External/Cache.php',
'OCA\\Files_Sharing\\External\\Manager' => __DIR__ . '/..' . '/../lib/External/Manager.php',
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php
index db92b8f3818..b470061c96b 100644
--- a/apps/files_sharing/lib/Controller/ShareAPIController.php
+++ b/apps/files_sharing/lib/Controller/ShareAPIController.php
@@ -12,6 +12,7 @@ declare(strict_types=1);
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Vincent Petry <pvince81@owncloud.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
+ * @author Maxence Lange <maxence@artificial-owl.com>
*
* @license AGPL-3.0
*
@@ -31,6 +32,8 @@ declare(strict_types=1);
namespace OCA\Files_Sharing\Controller;
+use OCA\Files_Sharing\Exceptions\SharingRightsException;
+use OCA\Files_Sharing\External\Storage;
use OCA\Files\Helper;
use OCA\Files_Sharing\External\Storage;
use OCP\App\IAppManager;
@@ -42,6 +45,7 @@ use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\QueryException;
use OCP\Constants;
+use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
@@ -383,7 +387,7 @@ class ShareAPIController extends OCSController {
* @throws OCSException
* @throws OCSForbiddenException
* @throws OCSNotFoundException
- * @throws \OCP\Files\InvalidPathException
+ * @throws InvalidPathException
* @suppress PhanUndeclaredClassMethod
*/
public function createShare(
@@ -579,11 +583,12 @@ class ShareAPIController extends OCSController {
}
/**
- * @param \OCP\Files\File|\OCP\Files\Folder $node
+ * @param null|Node $node
* @param boolean $includeTags
- * @return DataResponse
+ *
+ * @return array
*/
- private function getSharedWithMe($node = null, bool $includeTags): DataResponse {
+ private function getSharedWithMe($node, bool $includeTags): array {
$userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
$groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
@@ -592,7 +597,7 @@ class ShareAPIController extends OCSController {
$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
- $shares = array_filter($shares, function (IShare $share) {
+ $shares = array_filter($shares, function(IShare $share) {
return $share->getShareOwner() !== $this->currentUser;
});
@@ -611,13 +616,15 @@ class ShareAPIController extends OCSController {
$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
}
- return new DataResponse($formatted);
+ return $formatted;
}
/**
- * @param \OCP\Files\Folder $folder
+ * @param \OCP\Files\Node $folder
+ *
* @return array
* @throws OCSBadRequestException
+ * @throws NotFoundException
*/
private function getSharesInDir(Node $folder): array {
if (!($folder instanceof \OCP\Files\Folder)) {
@@ -638,15 +645,35 @@ class ShareAPIController extends OCSController {
if (in_array($share->getId(), $known)) {
return false;
}
- $known[] = $share->getId();
- return true;
- });
+
+ try {
+ $format = $this->formatShare($share);
+
+ $known[] = $share->getId();
+ $formatted[] = $format;
+ if ($share->getSharedBy() === $this->currentUser) {
+ $miniFormatted[] = $format;
+ }
+ if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
+ $resharingRight = true;
+ }
+ } catch (\Exception $e) {
+ //Ignore this share
+ }
+ }
+
+ if (!$resharingRight) {
+ $formatted = $miniFormatted;
+ }
+
+ return $formatted;
}
/**
* The getShares function.
*
* @NoAdminRequired
+ * @NoCSRFRequired
*
* @param string $shared_with_me
* @param string $reshares
@@ -659,64 +686,82 @@ class ShareAPIController extends OCSController {
* - Get shares for a specific path (?path=...)
* - Get all shares in a folder (?subfiles=true&path=..)
*
+ * @param string $include_tags
+ *
* @return DataResponse
+ * @throws NotFoundException
+ * @throws OCSBadRequestException
* @throws OCSNotFoundException
*/
public function getShares(
string $shared_with_me = 'false',
string $reshares = 'false',
string $subfiles = 'false',
- string $path = null,
+ string $path = '',
string $include_tags = 'false'
): DataResponse {
- if ($path !== null) {
+ $node = null;
+ if ($path !== '') {
$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
try {
- $path = $userFolder->get($path);
- $this->lock($path);
- } catch (\OCP\Files\NotFoundException $e) {
- throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
+ $node = $userFolder->get($path);
+ $this->lock($node);
+ } catch (NotFoundException $e) {
+ throw new OCSNotFoundException(
+ $this->l->t('Wrong path, file/folder doesn\'t exist')
+ );
} catch (LockedException $e) {
- throw new OCSNotFoundException($this->l->t('Could not lock path'));
+ throw new OCSNotFoundException($this->l->t('Could not lock node'));
}
}
- $include_tags = $include_tags === 'true';
+ $shares = $this->getFormattedShares(
+ $this->currentUser,
+ $node,
+ ($shared_with_me === 'true'),
+ ($reshares === 'true'),
+ ($subfiles === 'true'),
+ ($include_tags === 'true')
+ );
- if ($shared_with_me === 'true') {
- $result = $this->getSharedWithMe($path, $include_tags);
- return $result;
- }
+ return new DataResponse($shares);
+ }
- if ($reshares === 'true') {
- $reshares = true;
- } else {
- $reshares = false;
+
+ /**
+ * @param string $viewer
+ * @param Node $node
+ * @param bool $sharedWithMe
+ * @param bool $reShares
+ * @param bool $subFiles
+ * @param bool $includeTags
+ *
+ * @return array
+ * @throws NotFoundException
+ * @throws OCSBadRequestException
+ */
+ private function getFormattedShares(
+ string $viewer, $node = null, bool $sharedWithMe = false, bool $reShares = false,
+ bool $subFiles = false, bool $includeTags = false
+ ): array {
+
+ if ($sharedWithMe) {
+ return $this->getSharedWithMe($node, $includeTags);
}
- if ($subfiles === 'true') {
- $shares = $this->getSharesInDir($path);
- $recipientNode = null;
- } else {
- // get all shares
- $shares = $this->getAllShares($path, $reshares);
- $recipientNode = $path;
+ if ($subFiles) {
+ return $this->getSharesInDir($node);
}
- // process all shares
+ $shares = $this->getSharesFromNode($viewer, $node, $reShares);
+
$formatted = $miniFormatted = [];
$resharingRight = false;
foreach ($shares as $share) {
- /** @var IShare $share */
-
- // do not list the shares of the current user
- if ($share->getSharedWith() === $this->currentUser) {
- continue;
- }
-
try {
- $format = $this->formatShare($share, $recipientNode);
+ /** @var IShare $share */
+ $format = $this->formatShare($share, $node);
$formatted[] = $format;
// let's also build a list of shares created
@@ -731,8 +776,7 @@ class ShareAPIController extends OCSController {
if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $path)) {
$resharingRight = true;
}
- } catch (\Exception $e) {
- //Ignore share
+ } catch (InvalidPathException | NotFoundException $e) {
}
}
@@ -740,13 +784,89 @@ class ShareAPIController extends OCSController {
$formatted = $miniFormatted;
}
- if ($include_tags) {
- $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
+ if ($includeTags) {
+ $formatted =
+ Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
}
- return new DataResponse($formatted);
+ return $formatted;
}
+
+ /**
+ * The getInheritedShares function.
+ * returns all shares relative to a file, including parent folders shares rights.
+ *
+ * @NoAdminRequired
+ *
+ * @param string $path
+ *
+ * - Get shares by the current user
+ * - Get shares by the current user and reshares (?reshares=true)
+ * - Get shares with the current user (?shared_with_me=true)
+ * - Get shares for a specific path (?path=...)
+ * - Get all shares in a folder (?subfiles=true&path=..)
+ *
+ * @return DataResponse
+ * @throws InvalidPathException
+ * @throws NotFoundException
+ * @throws OCSNotFoundException
+ * @throws OCSBadRequestException
+ * @throws SharingRightsException
+ */
+ public function getInheritedShares(string $path): DataResponse {
+
+ // get Node from (string) path.
+ $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
+ try {
+ $node = $userFolder->get($path);
+ $this->lock($node);
+ } catch (\OCP\Files\NotFoundException $e) {
+ throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
+ } catch (LockedException $e) {
+ throw new OCSNotFoundException($this->l->t('Could not lock path'));
+ }
+
+ // current User has resharing rights ?
+ $this->confirmSharingRights($node);
+
+ // initiate real owner.
+ $owner = $node->getOwner()
+ ->getUID();
+ if (!$this->userManager->userExists($owner)) {
+ return new DataResponse([]);
+ }
+
+ // get node based on the owner, fix owner in case of external storage
+ $userFolder = $this->rootFolder->getUserFolder($owner);
+ if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
+ $owner = $node->getOwner()
+ ->getUID();
+ $userFolder = $this->rootFolder->getUserFolder($owner);
+ $nodes = $userFolder->getById($node->getId());
+ $node = array_shift($nodes);
+ }
+ $basePath = $userFolder->getPath();
+
+ // generate node list for each parent folders
+ /** @var Node[] $nodes */
+ $nodes = [];
+ while ($node->getPath() !== $basePath) {
+ $nodes[] = $node;
+ $node = $node->getParent();
+ }
+
+ // for each nodes, retrieve shares.
+ $shares = [];
+ foreach ($nodes as $node) {
+ $getShares = $this->getFormattedShares($owner, $node, false, true);
+ $this->mergeFormattedShares($shares, $getShares);
+ }
+
+ return new DataResponse(array_values($shares));
+ }
+
+
/**
* @NoAdminRequired
*
@@ -1262,6 +1382,90 @@ class ShareAPIController extends OCSController {
/**
+ * @param string $viewer
+ * @param Node $node
+ * @param bool $reShares
+ *
+ * @return IShare[]
+ */
+ private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
+
+ $providers = [
+ Share::SHARE_TYPE_USER,
+ Share::SHARE_TYPE_GROUP,
+ Share::SHARE_TYPE_LINK,
+ Share::SHARE_TYPE_EMAIL,
+ Share::SHARE_TYPE_EMAIL,
+ Share::SHARE_TYPE_CIRCLE,
+ Share::SHARE_TYPE_ROOM
+ ];
+
+ // Should we assume that the (currentUser) viewer is the owner of the node !?
+ $shares = [];
+ foreach ($providers as $provider) {
+ if (!$this->shareManager->shareProviderExists($provider)) {
+ continue;
+ }
+
+ $providerShares =
+ $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
+ $shares = array_merge($shares, $providerShares);
+ }
+
+ if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
+ $federatedShares = $this->shareManager->getSharesBy(
+ $this->currentUser, Share::SHARE_TYPE_REMOTE, $node, $reShares, -1, 0
+ );
+ $shares = array_merge($shares, $federatedShares);
+ }
+
+ if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
+ $federatedShares = $this->shareManager->getSharesBy(
+ $this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
+ );
+ $shares = array_merge($shares, $federatedShares);
+ }
+
+ return $shares;
+ }
+
+
+ /**
+ * @param Node $node
+ *
+ * @throws SharingRightsException
+ */
+ private function confirmSharingRights(Node $node): void {
+ if (!$this->hasResharingRights($this->currentUser, $node)) {
+ throw new SharingRightsException('no sharing rights on this item');
+ }
+ }
+
+
+ /**
+ * @param string $viewer
+ * @param Node $node
+ *
+ * @return bool
+ */
+ private function hasResharingRights($viewer, $node): bool {
+ foreach ([$node, $node->getParent()] as $node) {
+ $shares = $this->getSharesFromNode($viewer, $node, true);
+ foreach ($shares as $share) {
+ try {
+ if ($this->shareProviderResharingRights($viewer, $share, $node)) {
+ return true;
+ }
+ } catch (InvalidPathException | NotFoundException $e) {
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
* Returns if we can find resharing rights in an IShare object for a specific user.
*
* @suppress PhanUndeclaredClassMethod
@@ -1269,9 +1473,10 @@ class ShareAPIController extends OCSController {
* @param string $userId
* @param IShare $share
* @param Node $node
+ *
* @return bool
* @throws NotFoundException
- * @throws \OCP\Files\InvalidPathException
+ * @throws InvalidPathException
*/
private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
@@ -1280,7 +1485,7 @@ class ShareAPIController extends OCSController {
}
// we check that current user have parent resharing rights on the current file
- if ($node !== null && ($node->getPermissions() & \OCP\Constants::PERMISSION_SHARE) !== 0) {
+ if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
return true;
}
@@ -1357,4 +1562,21 @@ class ShareAPIController extends OCSController {
return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $federatedShares, $federatedGroupShares);
}
+
+ /**
+ * merging already formatted shares.
+ * We'll make an associative array to easily detect duplicate Ids.
+ * Keys _needs_ to be removed after all shares are retrieved and merged.
+ *
+ * @param array $shares
+ * @param array $newShares
+ */
+ private function mergeFormattedShares(array &$shares, array $newShares) {
+ foreach ($newShares as $newShare) {
+ if (!array_key_exists($newShare['id'], $shares)) {
+ $shares[$newShare['id']] = $newShare;
+ }
+ }
+ }
+
}
diff --git a/apps/files_sharing/lib/Exceptions/SharingRightsException.php b/apps/files_sharing/lib/Exceptions/SharingRightsException.php
new file mode 100644
index 00000000000..2ec496c0421
--- /dev/null
+++ b/apps/files_sharing/lib/Exceptions/SharingRightsException.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2019, Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Sharing\Exceptions;
+
+use Exception;
+
+
+/**
+ * Sharing and Resharing rights.
+ *
+ * Class SharingRightsException
+ *
+ * @package OCA\Files_Sharing\Exceptions
+ */
+class SharingRightsException extends Exception {
+
+}
+