diff options
author | Morris Jobke <hey@morrisjobke.de> | 2017-04-15 13:06:24 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-15 13:06:24 -0500 |
commit | 10290eb0060eb2194be2dd4fc8b707aa7eef5c0a (patch) | |
tree | b71665687f9c19f5b6f8e9f34ffbd5a8a2d4f5e8 /lib | |
parent | dafa9c740abee38bb54e9df05947bcf09857380a (diff) | |
parent | cab41118f67e6a4743bac2cfcfa69a4bee28f2a3 (diff) | |
download | nextcloud-server-10290eb0060eb2194be2dd4fc8b707aa7eef5c0a.tar.gz nextcloud-server-10290eb0060eb2194be2dd4fc8b707aa7eef5c0a.zip |
Merge pull request #2834 from nextcloud/accesListToShareManager
Access list to share manager
Diffstat (limited to 'lib')
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 2 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 2 | ||||
-rw-r--r-- | lib/private/Encryption/File.php | 35 | ||||
-rw-r--r-- | lib/private/Server.php | 14 | ||||
-rw-r--r-- | lib/private/Share20/DefaultShareProvider.php | 117 | ||||
-rw-r--r-- | lib/private/Share20/Manager.php | 105 | ||||
-rw-r--r-- | lib/private/Share20/ShareHelper.php | 217 | ||||
-rw-r--r-- | lib/public/Share/IManager.php | 47 | ||||
-rw-r--r-- | lib/public/Share/IShareHelper.php | 41 | ||||
-rw-r--r-- | lib/public/Share/IShareProvider.php | 12 |
10 files changed, 569 insertions, 23 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index a978a2ec575..823a876e04b 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -252,6 +252,7 @@ return array( 'OCP\\Share\\IManager' => $baseDir . '/lib/public/Share/IManager.php', 'OCP\\Share\\IProviderFactory' => $baseDir . '/lib/public/Share/IProviderFactory.php', 'OCP\\Share\\IShare' => $baseDir . '/lib/public/Share/IShare.php', + 'OCP\\Share\\IShareHelper' => $baseDir . '/lib/public/Share/IShareHelper.php', 'OCP\\Share\\IShareProvider' => $baseDir . '/lib/public/Share/IShareProvider.php', 'OCP\\Share_Backend' => $baseDir . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => $baseDir . '/lib/public/Share_Backend_Collection.php', @@ -804,6 +805,7 @@ return array( 'OC\\Share20\\Manager' => $baseDir . '/lib/private/Share20/Manager.php', 'OC\\Share20\\ProviderFactory' => $baseDir . '/lib/private/Share20/ProviderFactory.php', 'OC\\Share20\\Share' => $baseDir . '/lib/private/Share20/Share.php', + 'OC\\Share20\\ShareHelper' => $baseDir . '/lib/private/Share20/ShareHelper.php', 'OC\\Share\\Constants' => $baseDir . '/lib/private/Share/Constants.php', 'OC\\Share\\Helper' => $baseDir . '/lib/private/Share/Helper.php', 'OC\\Share\\MailNotifications' => $baseDir . '/lib/private/Share/MailNotifications.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 0967f0541ea..979679c4198 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -282,6 +282,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Share\\IManager' => __DIR__ . '/../../..' . '/lib/public/Share/IManager.php', 'OCP\\Share\\IProviderFactory' => __DIR__ . '/../../..' . '/lib/public/Share/IProviderFactory.php', 'OCP\\Share\\IShare' => __DIR__ . '/../../..' . '/lib/public/Share/IShare.php', + 'OCP\\Share\\IShareHelper' => __DIR__ . '/../../..' . '/lib/public/Share/IShareHelper.php', 'OCP\\Share\\IShareProvider' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProvider.php', 'OCP\\Share_Backend' => __DIR__ . '/../../..' . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_Collection.php', @@ -834,6 +835,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Share20\\Manager' => __DIR__ . '/../../..' . '/lib/private/Share20/Manager.php', 'OC\\Share20\\ProviderFactory' => __DIR__ . '/../../..' . '/lib/private/Share20/ProviderFactory.php', 'OC\\Share20\\Share' => __DIR__ . '/../../..' . '/lib/private/Share20/Share.php', + 'OC\\Share20\\ShareHelper' => __DIR__ . '/../../..' . '/lib/private/Share20/ShareHelper.php', 'OC\\Share\\Constants' => __DIR__ . '/../../..' . '/lib/private/Share/Constants.php', 'OC\\Share\\Helper' => __DIR__ . '/../../..' . '/lib/private/Share/Helper.php', 'OC\\Share\\MailNotifications' => __DIR__ . '/../../..' . '/lib/private/Share/MailNotifications.php', diff --git a/lib/private/Encryption/File.php b/lib/private/Encryption/File.php index 240a8f1ccab..2bc0e014f0c 100644 --- a/lib/private/Encryption/File.php +++ b/lib/private/Encryption/File.php @@ -25,12 +25,21 @@ namespace OC\Encryption; use OC\Cache\CappedMemoryCache; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\Share\IManager; class File implements \OCP\Encryption\IFile { /** @var Util */ protected $util; + /** @var IRootFolder */ + private $rootFolder; + + /** @var IManager */ + private $shareManager; + /** * cache results of already checked folders * @@ -38,9 +47,13 @@ class File implements \OCP\Encryption\IFile { */ protected $cache; - public function __construct(Util $util) { + public function __construct(Util $util, + IRootFolder $rootFolder, + IManager $shareManager) { $this->util = $util; $this->cache = new CappedMemoryCache(); + $this->rootFolder = $rootFolder; + $this->shareManager = $shareManager; } @@ -63,26 +76,34 @@ class File implements \OCP\Encryption\IFile { } $ownerPath = substr($ownerPath, strlen('/files')); + $userFolder = $this->rootFolder->getUserFolder($owner); + try { + $file = $userFolder->get($ownerPath); + } catch (NotFoundException $e) { + $file = null; + } $ownerPath = $this->util->stripPartialFileExtension($ownerPath); - // first get the shares for the parent and cache the result so that we don't // need to check all parents for every file $parent = dirname($ownerPath); + $parentNode = $userFolder->get($parent); if (isset($this->cache[$parent])) { $resultForParents = $this->cache[$parent]; } else { - $resultForParents = \OCP\Share::getUsersSharingFile($parent, $owner); + $resultForParents = $this->shareManager->getAccessList($parentNode); $this->cache[$parent] = $resultForParents; } - $userIds = \array_merge($userIds, $resultForParents['users']); + $userIds = array_merge($userIds, $resultForParents['users']); $public = $resultForParents['public'] || $resultForParents['remote']; // Find out who, if anyone, is sharing the file - $resultForFile = \OCP\Share::getUsersSharingFile($ownerPath, $owner, false, false, false); - $userIds = \array_merge($userIds, $resultForFile['users']); - $public = $resultForFile['public'] || $resultForFile['remote'] || $public; + if ($file !== null) { + $resultForFile = $this->shareManager->getAccessList($file, false); + $userIds = array_merge($userIds, $resultForFile['users']); + $public = $resultForFile['public'] || $resultForFile['remote'] || $public; + } // check if it is a group mount if (\OCP\App::isEnabled("files_external")) { diff --git a/lib/private/Server.php b/lib/private/Server.php index 1ee34a57b93..62c17ced90b 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -93,6 +93,7 @@ use OC\Security\CredentialsManager; use OC\Security\SecureRandom; use OC\Security\TrustedDomainHelper; use OC\Session\CryptoWrapper; +use OC\Share20\ShareHelper; use OC\Tagging\TagMapper; use OCA\Theming\ThemingDefaults; use OCP\App\IAppManager; @@ -106,6 +107,7 @@ use OCP\IServerContainer; use OCP\ITempManager; use OCP\RichObjectStrings\IValidator; use OCP\Security\IContentSecurityPolicyManager; +use OCP\Share\IShareHelper; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -173,7 +175,11 @@ class Server extends ServerContainer implements IServerContainer { $c->getGroupManager(), $c->getConfig() ); - return new Encryption\File($util); + return new Encryption\File( + $util, + $c->getRootFolder(), + $c->getShareManager() + ); }); $this->registerService('EncryptionKeyStorage', function (Server $c) { @@ -988,6 +994,12 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService(\OCP\ISession::class, function(SimpleContainer $c) { return $c->query(\OCP\IUserSession::class)->getSession(); }); + + $this->registerService(IShareHelper::class, function(Server $c) { + return new ShareHelper( + $c->query(\OCP\Share\IManager::class) + ); + }); } /** diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index feae147066d..ed3651df9b2 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -362,7 +362,7 @@ class DefaultShareProvider implements IShareProvider { if ($data === false) { $qb = $this->dbConn->getQueryBuilder(); - $type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder'; + $type = $share->getNodeType(); //Insert new share $qb->insert('share') @@ -373,8 +373,8 @@ class DefaultShareProvider implements IShareProvider { 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()), 'parent' => $qb->createNamedParameter($share->getId()), 'item_type' => $qb->createNamedParameter($type), - 'item_source' => $qb->createNamedParameter($share->getNode()->getId()), - 'file_source' => $qb->createNamedParameter($share->getNode()->getId()), + 'item_source' => $qb->createNamedParameter($share->getNodeId()), + 'file_source' => $qb->createNamedParameter($share->getNodeId()), 'file_target' => $qb->createNamedParameter($share->getTarget()), 'permissions' => $qb->createNamedParameter(0), 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()), @@ -1070,4 +1070,115 @@ class DefaultShareProvider implements IShareProvider { } } } + + /** + * @inheritdoc + */ + public function getAccessList($nodes, $currentAccess) { + $ids = []; + foreach ($nodes as $node) { + $ids[] = $node->getId(); + } + + $qb = $this->dbConn->getQueryBuilder(); + + $or = $qb->expr()->orX( + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)), + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)), + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)) + ); + + if ($currentAccess) { + $or->add($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))); + } + + $qb->select('id', 'parent', 'share_type', 'share_with', 'file_source', 'file_target', 'permissions') + ->from('share') + ->where( + $or + ) + ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) + ->andWhere($qb->expr()->orX( + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) + )); + $cursor = $qb->execute(); + + $users = []; + $link = false; + while($row = $cursor->fetch()) { + $type = (int)$row['share_type']; + if ($type === \OCP\Share::SHARE_TYPE_USER) { + $uid = $row['share_with']; + $users[$uid] = isset($users[$uid]) ? $users[$uid] : []; + $users[$uid][$row['id']] = $row; + } else if ($type === \OCP\Share::SHARE_TYPE_GROUP) { + $gid = $row['share_with']; + $group = $this->groupManager->get($gid); + + if ($gid === null) { + continue; + } + + $userList = $group->getUsers(); + foreach ($userList as $user) { + $uid = $user->getUID(); + $users[$uid] = isset($users[$uid]) ? $users[$uid] : []; + $users[$uid][$row['id']] = $row; + } + } else if ($type === \OCP\Share::SHARE_TYPE_LINK) { + $link = true; + } else if ($type === self::SHARE_TYPE_USERGROUP && $currentAccess === true) { + $uid = $row['share_with']; + $users[$uid] = isset($users[$uid]) ? $users[$uid] : []; + $users[$uid][$row['id']] = $row; + } + } + $cursor->closeCursor(); + + if ($currentAccess === true) { + $users = array_map([$this, 'filterSharesOfUser'], $users); + $users = array_filter($users); + } else { + $users = array_keys($users); + } + + return ['users' => $users, 'public' => $link]; + } + + /** + * For each user the path with the fewest slashes is returned + * @param array $shares + * @return array + */ + protected function filterSharesOfUser(array $shares) { + // Group shares when the user has a share exception + foreach ($shares as $id => $share) { + $type = (int) $share['share_type']; + $permissions = (int) $share['permissions']; + + if ($type === self::SHARE_TYPE_USERGROUP) { + unset($shares[$share['parent']]); + + if ($permissions === 0) { + unset($shares[$id]); + } + } + } + + $best = []; + $bestDepth = 0; + foreach ($shares as $id => $share) { + $depth = substr_count($share['file_target'], '/'); + if (empty($best) || $depth < $bestDepth) { + $bestDepth = $depth; + $best = [ + 'node_id' => $share['file_source'], + 'node_path' => $share['file_target'], + ]; + } + } + + return $best; + } } diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 292b07d28d5..6e59629153e 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -48,6 +48,7 @@ use OCP\Share\Exceptions\GenericShareException; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager; use OCP\Share\IProviderFactory; +use OCP\Share\IShare; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\GenericEvent; use OCP\Share\IShareProvider; @@ -1176,29 +1177,109 @@ class Manager implements IManager { /** * Get access list to a path. This means - * all the users and groups that can access a given path. + * all the users that can access a given path. * * Consider: * -root - * |-folder1 - * |-folder2 - * |-fileA + * |-folder1 (23) + * |-folder2 (32) + * |-fileA (42) * - * fileA is shared with user1 - * folder2 is shared with group2 - * folder1 is shared with user2 + * fileA is shared with user1 and user1@server1 + * folder2 is shared with group2 (user4 is a member of group2) + * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2 * - * Then the access list will to '/folder1/folder2/fileA' is: + * Then the access list to '/folder1/folder2/fileA' with $currentAccess is: * [ - * 'users' => ['user1', 'user2'], - * 'groups' => ['group2'] + * users => [ + * 'user1' => ['node_id' => 42, 'node_path' => '/fileA'], + * 'user4' => ['node_id' => 32, 'node_path' => '/folder2'], + * 'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'], + * ], + * remote => [ + * 'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'], + * 'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'], + * ], + * public => bool + * mail => bool * ] * - * This is required for encryption + * The access list to '/folder1/folder2/fileA' **without** $currentAccess is: + * [ + * users => ['user1', 'user2', 'user4'], + * remote => bool, + * public => bool + * mail => bool + * ] + * + * This is required for encryption/activity * * @param \OCP\Files\Node $path + * @param bool $recursive Should we check all parent folders as well + * @param bool $currentAccess Should the user have currently access to the file + * @return array */ - public function getAccessList(\OCP\Files\Node $path) { + public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) { + $owner = $path->getOwner()->getUID(); + + if ($currentAccess) { + $al = ['users' => [], 'remote' => [], 'public' => false]; + } else { + $al = ['users' => [], 'remote' => false, 'public' => false]; + } + if (!$this->userManager->userExists($owner)) { + return $al; + } + + //Get node for the owner + $userFolder = $this->rootFolder->getUserFolder($owner); + if (!$userFolder->isSubNode($path)) { + $path = $userFolder->getById($path->getId())[0]; + } + + $providers = $this->factory->getAllProviders(); + + /** @var Node[] $nodes */ + $nodes = []; + + + if ($currentAccess) { + $ownerPath = $path->getPath(); + list(, , , $ownerPath) = explode('/', $ownerPath, 4); + $al['users'][$owner] = [ + 'node_id' => $path->getId(), + 'node_path' => '/' . $ownerPath, + ]; + } else { + $al['users'][] = $owner; + } + + // Collect all the shares + while ($path->getPath() !== $userFolder->getPath()) { + $nodes[] = $path; + if (!$recursive) { + break; + } + $path = $path->getParent(); + } + + foreach ($providers as $provider) { + $tmp = $provider->getAccessList($nodes, $currentAccess); + + foreach ($tmp as $k => $v) { + if (isset($al[$k])) { + if (is_array($al[$k])) { + $al[$k] = array_merge($al[$k], $v); + } else { + $al[$k] = $al[$k] || $v; + } + } else { + $al[$k] = $v; + } + } + } + + return $al; } /** diff --git a/lib/private/Share20/ShareHelper.php b/lib/private/Share20/ShareHelper.php new file mode 100644 index 00000000000..358b4e8026a --- /dev/null +++ b/lib/private/Share20/ShareHelper.php @@ -0,0 +1,217 @@ +<?php +/** + * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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 OC\Share20; + +use OCP\Files\InvalidPathException; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use OCP\Share\IManager; +use OCP\Share\IShareHelper; + +class ShareHelper implements IShareHelper { + + /** @var IManager */ + private $shareManager; + + public function __construct(IManager $shareManager) { + $this->shareManager = $shareManager; + } + + /** + * @param Node $node + * @return array [ users => [Mapping $uid => $pathForUser], remotes => [Mapping $cloudId => $pathToMountRoot]] + */ + public function getPathsForAccessList(Node $node) { + $result = [ + 'users' => [], + 'remotes' => [], + ]; + + $accessList = $this->shareManager->getAccessList($node, true, true); + if (!empty($accessList['users'])) { + $result['users'] = $this->getPathsForUsers($node, $accessList['users']); + } + if (!empty($accessList['remote'])) { + $result['remotes'] = $this->getPathsForRemotes($node, $accessList['remote']); + } + + return $result; + } + + /** + * Sample: + * $users = [ + * 'test1' => ['node_id' => 16, 'node_path' => '/foo'], + * 'test2' => ['node_id' => 23, 'node_path' => '/bar'], + * 'test3' => ['node_id' => 42, 'node_path' => '/cat'], + * 'test4' => ['node_id' => 48, 'node_path' => '/dog'], + * ]; + * + * Node tree: + * - SixTeen is the parent of TwentyThree + * - TwentyThree is the parent of FortyTwo + * - FortyEight does not exist + * + * $return = [ + * 'test1' => '/foo/TwentyThree/FortyTwo', + * 'test2' => '/bar/FortyTwo', + * 'test3' => '/cat', + * ], + * + * @param Node $node + * @param array[] $users + * @return array + */ + protected function getPathsForUsers(Node $node, array $users) { + /** @var array[] $byId */ + $byId = []; + /** @var array[] $results */ + $results = []; + + foreach ($users as $uid => $info) { + if (!isset($byId[$info['node_id']])) { + $byId[$info['node_id']] = []; + } + $byId[$info['node_id']][$uid] = $info['node_path']; + } + + try { + if (isset($byId[$node->getId()])) { + foreach ($byId[$node->getId()] as $uid => $path) { + $results[$uid] = $path; + } + unset($byId[$node->getId()]); + } + } catch (NotFoundException $e) { + return $results; + } catch (InvalidPathException $e) { + return $results; + } + + if (empty($byId)) { + return $results; + } + + $item = $node; + $appendix = '/' . $node->getName(); + while (!empty($byId)) { + try { + /** @var Node $item */ + $item = $item->getParent(); + + if (!empty($byId[$item->getId()])) { + foreach ($byId[$item->getId()] as $uid => $path) { + $results[$uid] = $path . $appendix; + } + unset($byId[$item->getId()]); + } + + $appendix = '/' . $item->getName() . $appendix; + } catch (NotFoundException $e) { + return $results; + } catch (InvalidPathException $e) { + return $results; + } catch (NotPermittedException $e) { + return $results; + } + } + + return $results; + } + + /** + * Sample: + * $remotes = [ + * 'test1' => ['node_id' => 16, 'token' => 't1'], + * 'test2' => ['node_id' => 23, 'token' => 't2'], + * 'test3' => ['node_id' => 42, 'token' => 't3'], + * 'test4' => ['node_id' => 48, 'token' => 't4'], + * ]; + * + * Node tree: + * - SixTeen is the parent of TwentyThree + * - TwentyThree is the parent of FortyTwo + * - FortyEight does not exist + * + * $return = [ + * 'test1' => ['token' => 't1', 'node_path' => '/SixTeen'], + * 'test2' => ['token' => 't2', 'node_path' => '/SixTeen/TwentyThree'], + * 'test3' => ['token' => 't3', 'node_path' => '/SixTeen/TwentyThree/FortyTwo'], + * ], + * + * @param Node $node + * @param array[] $remotes + * @return array + */ + protected function getPathsForRemotes(Node $node, array $remotes) { + /** @var array[] $byId */ + $byId = []; + /** @var array[] $results */ + $results = []; + + foreach ($remotes as $cloudId => $info) { + if (!isset($byId[$info['node_id']])) { + $byId[$info['node_id']] = []; + } + $byId[$info['node_id']][$cloudId] = $info['token']; + } + + $item = $node; + while (!empty($byId)) { + try { + if (!empty($byId[$item->getId()])) { + $path = $this->getMountedPath($item); + foreach ($byId[$item->getId()] as $uid => $token) { + $results[$uid] = [ + 'node_path' => $path, + 'token' => $token, + ]; + } + unset($byId[$item->getId()]); + } + + /** @var Node $item */ + $item = $item->getParent(); + } catch (NotFoundException $e) { + return $results; + } catch (InvalidPathException $e) { + return $results; + } catch (NotPermittedException $e) { + return $results; + } + } + + return $results; + } + + /** + * @param Node $node + * @return string + */ + protected function getMountedPath(Node $node) { + $path = $node->getPath(); + $sections = explode('/', $path, 4); + return '/' . $sections[3]; + } +} diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php index a15020bbd69..31f04803066 100644 --- a/lib/public/Share/IManager.php +++ b/lib/public/Share/IManager.php @@ -192,6 +192,53 @@ interface IManager { public function userDeletedFromGroup($uid, $gid); /** + * Get access list to a path. This means + * all the users that can access a given path. + * + * Consider: + * -root + * |-folder1 (23) + * |-folder2 (32) + * |-fileA (42) + * + * fileA is shared with user1 and user1@server1 + * folder2 is shared with group2 (user4 is a member of group2) + * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2 + * + * Then the access list to '/folder1/folder2/fileA' with $currentAccess is: + * [ + * users => [ + * 'user1' => ['node_id' => 42, 'node_path' => '/fileA'], + * 'user4' => ['node_id' => 32, 'node_path' => '/folder2'], + * 'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'], + * ], + * remote => [ + * 'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'], + * 'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'], + * ], + * public => bool + * mail => bool + * ] + * + * The access list to '/folder1/folder2/fileA' **without** $currentAccess is: + * [ + * users => ['user1', 'user2', 'user4'], + * remote => bool, + * public => bool + * mail => bool + * ] + * + * This is required for encryption/activity + * + * @param \OCP\Files\Node $path + * @param bool $recursive Should we check all parent folders as well + * @param bool $currentAccess Should the user have currently access to the file + * @return array + * @since 12 + */ + public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false); + + /** * Instantiates a new share object. This is to be passed to * createShare. * diff --git a/lib/public/Share/IShareHelper.php b/lib/public/Share/IShareHelper.php new file mode 100644 index 00000000000..4ec62830c52 --- /dev/null +++ b/lib/public/Share/IShareHelper.php @@ -0,0 +1,41 @@ +<?php +/** + * @copyright 2017, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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 OCP\Share; + +use OCP\Files\Node; + +/** + * Interface IShareHelper + * + * @package OCP\Share + * @since 12 + */ +interface IShareHelper { + + /** + * @param Node $node + * @return array [ users => [Mapping $uid => $pathForUser], remotes => [Mapping $cloudId => $pathToMountRoot]] + * @since 12 + */ + public function getPathsForAccessList(Node $node); +} diff --git a/lib/public/Share/IShareProvider.php b/lib/public/Share/IShareProvider.php index 6257c97eb77..31808206cf6 100644 --- a/lib/public/Share/IShareProvider.php +++ b/lib/public/Share/IShareProvider.php @@ -190,4 +190,16 @@ interface IShareProvider { * @since 9.1.0 */ public function userDeletedFromGroup($uid, $gid); + + /** + * Get the access list to the array of provided nodes. + * + * @see IManager::getAccessList() for sample docs + * + * @param Node[] $nodes The list of nodes to get access for + * @param bool $currentAccess If current access is required (like for removed shares that might get revived later) + * @return array + * @since 12 + */ + public function getAccessList($nodes, $currentAccess); } |