Browse Source
Merge pull request #2834 from nextcloud/accesListToShareManager
Merge pull request #2834 from nextcloud/accesListToShareManager
Access list to share managerpull/3054/merge
committed by
GitHub
17 changed files with 1287 additions and 32 deletions
-
40apps/federatedfilesharing/lib/FederatedShareProvider.php
-
58apps/federatedfilesharing/tests/FederatedShareProviderTest.php
-
27apps/sharebymail/lib/ShareByMailProvider.php
-
62apps/sharebymail/tests/ShareByMailProviderTest.php
-
2lib/composer/composer/autoload_classmap.php
-
2lib/composer/composer/autoload_static.php
-
35lib/private/Encryption/File.php
-
14lib/private/Server.php
-
117lib/private/Share20/DefaultShareProvider.php
-
105lib/private/Share20/Manager.php
-
217lib/private/Share20/ShareHelper.php
-
47lib/public/Share/IManager.php
-
41lib/public/Share/IShareHelper.php
-
12lib/public/Share/IShareProvider.php
-
187tests/lib/Share20/DefaultShareProviderTest.php
-
122tests/lib/Share20/ManagerTest.php
-
231tests/lib/Share20/ShareHelperTest.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]; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -0,0 +1,231 @@ |
|||
<?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 Test\Share20; |
|||
|
|||
use OC\Share20\ShareHelper; |
|||
use OCP\Files\Node; |
|||
use OCP\Files\NotFoundException; |
|||
use OCP\Share\IManager; |
|||
use Test\TestCase; |
|||
|
|||
class ShareHelperTest extends TestCase { |
|||
|
|||
/** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $manager; |
|||
|
|||
/** @var ShareHelper */ |
|||
private $helper; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$this->manager = $this->createMock(IManager::class); |
|||
|
|||
$this->helper = new ShareHelper($this->manager); |
|||
} |
|||
|
|||
public function dataGetPathsForAccessList() { |
|||
return [ |
|||
[[], [], false, [], [], false, [ |
|||
'users' => [], |
|||
'remotes' => [], |
|||
]], |
|||
[['user1', 'user2'], ['user1' => 'foo', 'user2' => 'bar'], true, [], [], false, [ |
|||
'users' => ['user1' => 'foo', 'user2' => 'bar'], |
|||
'remotes' => [], |
|||
]], |
|||
[[], [], false, ['remote1', 'remote2'], ['remote1' => 'qwe', 'remote2' => 'rtz'], true, [ |
|||
'users' => [], |
|||
'remotes' => ['remote1' => 'qwe', 'remote2' => 'rtz'], |
|||
]], |
|||
[['user1', 'user2'], ['user1' => 'foo', 'user2' => 'bar'], true, ['remote1', 'remote2'], ['remote1' => 'qwe', 'remote2' => 'rtz'], true, [ |
|||
'users' => ['user1' => 'foo', 'user2' => 'bar'], |
|||
'remotes' => ['remote1' => 'qwe', 'remote2' => 'rtz'], |
|||
]], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider dataGetPathsForAccessList |
|||
*/ |
|||
public function testGetPathsForAccessList(array $userList, array $userMap, $resolveUsers, array $remoteList, array $remoteMap, $resolveRemotes, array $expected) { |
|||
$this->manager->expects($this->once()) |
|||
->method('getAccessList') |
|||
->willReturn([ |
|||
'users' => $userList, |
|||
'remote' => $remoteList, |
|||
]); |
|||
|
|||
/** @var Node|\PHPUnit_Framework_MockObject_MockObject $node */ |
|||
$node = $this->createMock(Node::class); |
|||
/** @var ShareHelper|\PHPUnit_Framework_MockObject_MockObject $helper */ |
|||
$helper = $this->getMockBuilder(ShareHelper::class) |
|||
->setConstructorArgs([$this->manager]) |
|||
->setMethods(['getPathsForUsers', 'getPathsForRemotes']) |
|||
->getMock(); |
|||
|
|||
$helper->expects($resolveUsers ? $this->once() : $this->never()) |
|||
->method('getPathsForUsers') |
|||
->with($node, $userList) |
|||
->willReturn($userMap); |
|||
|
|||
$helper->expects($resolveRemotes ? $this->once() : $this->never()) |
|||
->method('getPathsForRemotes') |
|||
->with($node, $remoteList) |
|||
->willReturn($remoteMap); |
|||
|
|||
$this->assertSame($expected, $helper->getPathsForAccessList($node)); |
|||
} |
|||
|
|||
public function dataGetPathsForUsers() { |
|||
return [ |
|||
[[], [23 => 'TwentyThree', 42 => 'FortyTwo'], []], |
|||
[ |
|||
[ |
|||
'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'], |
|||
], |
|||
[16 => 'SixTeen', 23 => 'TwentyThree', 42 => 'FortyTwo'], |
|||
[ |
|||
'test1' => '/foo/TwentyThree/FortyTwo', |
|||
'test2' => '/bar/FortyTwo', |
|||
'test3' => '/cat', |
|||
], |
|||
], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider dataGetPathsForUsers |
|||
* |
|||
* @param array $users |
|||
* @param array $nodes |
|||
* @param array $expected |
|||
*/ |
|||
public function testGetPathsForUsers(array $users, array $nodes, array $expected) { |
|||
$lastNode = null; |
|||
foreach ($nodes as $nodeId => $nodeName) { |
|||
/** @var Node|\PHPUnit_Framework_MockObject_MockObject $node */ |
|||
$node = $this->createMock(Node::class); |
|||
$node->expects($this->any()) |
|||
->method('getId') |
|||
->willReturn($nodeId); |
|||
$node->expects($this->any()) |
|||
->method('getName') |
|||
->willReturn($nodeName); |
|||
if ($lastNode === null) { |
|||
$node->expects($this->any()) |
|||
->method('getParent') |
|||
->willThrowException(new NotFoundException()); |
|||
} else { |
|||
$node->expects($this->any()) |
|||
->method('getParent') |
|||
->willReturn($lastNode); |
|||
} |
|||
$lastNode = $node; |
|||
} |
|||
|
|||
$this->assertEquals($expected, self::invokePrivate($this->helper, 'getPathsForUsers', [$lastNode, $users])); |
|||
} |
|||
|
|||
public function dataGetPathsForRemotes() { |
|||
return [ |
|||
[[], [23 => 'TwentyThree', 42 => 'FortyTwo'], []], |
|||
[ |
|||
[ |
|||
'test1' => ['node_id' => 16, 'token' => 't1'], |
|||
'test2' => ['node_id' => 23, 'token' => 't2'], |
|||
'test3' => ['node_id' => 42, 'token' => 't3'], |
|||
'test4' => ['node_id' => 48, 'token' => 't4'], |
|||
], |
|||
[ |
|||
16 => '/admin/files/SixTeen', |
|||
23 => '/admin/files/SixTeen/TwentyThree', |
|||
42 => '/admin/files/SixTeen/TwentyThree/FortyTwo', |
|||
], |
|||
[ |
|||
'test1' => ['token' => 't1', 'node_path' => '/SixTeen'], |
|||
'test2' => ['token' => 't2', 'node_path' => '/SixTeen/TwentyThree'], |
|||
'test3' => ['token' => 't3', 'node_path' => '/SixTeen/TwentyThree/FortyTwo'], |
|||
], |
|||
], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider dataGetPathsForRemotes |
|||
* |
|||
* @param array $remotes |
|||
* @param array $nodes |
|||
* @param array $expected |
|||
*/ |
|||
public function testGetPathsForRemotes(array $remotes, array $nodes, array $expected) { |
|||
$lastNode = null; |
|||
foreach ($nodes as $nodeId => $nodePath) { |
|||
/** @var Node|\PHPUnit_Framework_MockObject_MockObject $node */ |
|||
$node = $this->createMock(Node::class); |
|||
$node->expects($this->any()) |
|||
->method('getId') |
|||
->willReturn($nodeId); |
|||
$node->expects($this->any()) |
|||
->method('getPath') |
|||
->willReturn($nodePath); |
|||
if ($lastNode === null) { |
|||
$node->expects($this->any()) |
|||
->method('getParent') |
|||
->willThrowException(new NotFoundException()); |
|||
} else { |
|||
$node->expects($this->any()) |
|||
->method('getParent') |
|||
->willReturn($lastNode); |
|||
} |
|||
$lastNode = $node; |
|||
} |
|||
|
|||
$this->assertEquals($expected, self::invokePrivate($this->helper, 'getPathsForRemotes', [$lastNode, $remotes])); |
|||
} |
|||
|
|||
public function dataGetMountedPath() { |
|||
return [ |
|||
['/admin/files/foobar', '/foobar'], |
|||
['/admin/files/foo/bar', '/foo/bar'], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider dataGetMountedPath |
|||
* @param string $path |
|||
* @param string $expected |
|||
*/ |
|||
public function testGetMountedPath($path, $expected) { |
|||
/** @var Node|\PHPUnit_Framework_MockObject_MockObject $node */ |
|||
$node = $this->createMock(Node::class); |
|||
$node->expects($this->once()) |
|||
->method('getPath') |
|||
->willReturn($path); |
|||
|
|||
$this->assertSame($expected, self::invokePrivate($this->helper, 'getMountedPath', [$node])); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue