Browse Source
Add share attributes + prevent download permission
Add share attributes + prevent download permission
Makes it possible to store download permission Signed-off-by: Vincent Petry <vincent@nextcloud.com>pull/32482/head
committed by
Carl Schwan
No known key found for this signature in database
GPG Key ID: C3AA6B3A5EFA7AC5
28 changed files with 1189 additions and 51 deletions
-
1apps/dav/composer/composer/autoload_classmap.php
-
1apps/dav/composer/composer/autoload_static.php
-
6apps/dav/lib/Connector/Sabre/ServerFactory.php
-
113apps/dav/lib/DAV/ViewOnlyPlugin.php
-
6apps/dav/lib/Server.php
-
118apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php
-
9apps/files/js/fileinfomodel.js
-
1apps/files_sharing/composer/composer/autoload_classmap.php
-
1apps/files_sharing/composer/composer/autoload_static.php
-
68apps/files_sharing/lib/AppInfo/Application.php
-
31apps/files_sharing/lib/Controller/ShareAPIController.php
-
29apps/files_sharing/lib/MountProvider.php
-
116apps/files_sharing/lib/ViewOnly.php
-
7apps/files_sharing/tests/ApiTest.php
-
238apps/files_sharing/tests/ApplicationTest.php
-
49apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
-
97apps/files_sharing/tests/MountProviderTest.php
-
2lib/composer/composer/autoload_classmap.php
-
2lib/composer/composer/autoload_static.php
-
66lib/private/Share20/DefaultShareProvider.php
-
14lib/private/Share20/Manager.php
-
27lib/private/Share20/Share.php
-
73lib/private/Share20/ShareAttributes.php
-
33lib/private/legacy/OC_Files.php
-
68lib/public/Share/IAttributes.php
-
27lib/public/Share/IShare.php
-
31tests/lib/Share20/DefaultShareProviderTest.php
-
6tests/lib/Share20/ManagerTest.php
@ -0,0 +1,113 @@ |
|||
<?php |
|||
/** |
|||
* @author Piotr Mrowczynski piotr@owncloud.com |
|||
* |
|||
* @copyright Copyright (c) 2019, ownCloud GmbH |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\DAV\DAV; |
|||
|
|||
use OCA\DAV\Connector\Sabre\Exception\Forbidden; |
|||
use OCA\DAV\Connector\Sabre\File as DavFile; |
|||
use OCA\DAV\Meta\MetaFile; |
|||
use OCP\Files\FileInfo; |
|||
use OCP\Files\NotFoundException; |
|||
use OCP\ILogger; |
|||
use Sabre\DAV\Server; |
|||
use Sabre\DAV\ServerPlugin; |
|||
use Sabre\HTTP\RequestInterface; |
|||
use Sabre\DAV\Exception\NotFound; |
|||
|
|||
/** |
|||
* Sabre plugin for restricting file share receiver download: |
|||
*/ |
|||
class ViewOnlyPlugin extends ServerPlugin { |
|||
|
|||
/** @var Server $server */ |
|||
private $server; |
|||
|
|||
/** @var ILogger $logger */ |
|||
private $logger; |
|||
|
|||
/** |
|||
* @param ILogger $logger |
|||
*/ |
|||
public function __construct(ILogger $logger) { |
|||
$this->logger = $logger; |
|||
} |
|||
|
|||
/** |
|||
* This initializes the plugin. |
|||
* |
|||
* This function is called by Sabre\DAV\Server, after |
|||
* addPlugin is called. |
|||
* |
|||
* This method should set up the required event subscriptions. |
|||
* |
|||
* @param Server $server |
|||
* @return void |
|||
*/ |
|||
public function initialize(Server $server) { |
|||
$this->server = $server; |
|||
//priority 90 to make sure the plugin is called before
|
|||
//Sabre\DAV\CorePlugin::httpGet
|
|||
$this->server->on('method:GET', [$this, 'checkViewOnly'], 90); |
|||
} |
|||
|
|||
/** |
|||
* Disallow download via DAV Api in case file being received share |
|||
* and having special permission |
|||
* |
|||
* @param RequestInterface $request request object |
|||
* @return boolean |
|||
* @throws Forbidden |
|||
* @throws NotFoundException |
|||
*/ |
|||
public function checkViewOnly( |
|||
RequestInterface $request |
|||
) { |
|||
$path = $request->getPath(); |
|||
|
|||
try { |
|||
$davNode = $this->server->tree->getNodeForPath($path); |
|||
if (!($davNode instanceof DavFile)) { |
|||
return true; |
|||
} |
|||
// Restrict view-only to nodes which are shared
|
|||
$node = $davNode->getNode(); |
|||
|
|||
$storage = $node->getStorage(); |
|||
// using string as we have no guarantee that "files_sharing" app is loaded
|
|||
if (!$storage->instanceOfStorage('OCA\Files_Sharing\SharedStorage')) { |
|||
return true; |
|||
} |
|||
// Extract extra permissions
|
|||
/** @var \OCA\Files_Sharing\SharedStorage $storage */ |
|||
$share = $storage->getShare(); |
|||
|
|||
// Check if read-only and on whether permission can download is both set and disabled.
|
|||
$canDownload = $share->getAttributes()->getAttribute('permissions', 'download'); |
|||
if ($canDownload !== null && !$canDownload) { |
|||
throw new Forbidden('Access to this resource has been denied because it is in view-only mode.'); |
|||
} |
|||
} catch (NotFound $e) { |
|||
$this->logger->warning($e->getMessage()); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
@ -0,0 +1,118 @@ |
|||
<?php |
|||
/** |
|||
* @author Piotr Mrowczynski piotr@owncloud.com |
|||
* |
|||
* @copyright Copyright (c) 2019, ownCloud GmbH |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
namespace OCA\DAV\Tests\unit\DAV; |
|||
|
|||
use OCA\DAV\DAV\ViewOnlyPlugin; |
|||
use OCA\Files_Sharing\SharedStorage; |
|||
use OCA\DAV\Connector\Sabre\File as DavFile; |
|||
use OCP\Files\File; |
|||
use OCP\Files\Storage\IStorage; |
|||
use OCP\ILogger; |
|||
use OCP\Share\IAttributes; |
|||
use OCP\Share\IShare; |
|||
use Sabre\DAV\Server; |
|||
use Sabre\DAV\Tree; |
|||
use Test\TestCase; |
|||
use Sabre\HTTP\RequestInterface; |
|||
use OCA\DAV\Connector\Sabre\Exception\Forbidden; |
|||
|
|||
class ViewOnlyPluginTest extends TestCase { |
|||
|
|||
/** @var ViewOnlyPlugin */ |
|||
private $plugin; |
|||
/** @var Tree | \PHPUnit\Framework\MockObject\MockObject */ |
|||
private $tree; |
|||
/** @var RequestInterface | \PHPUnit\Framework\MockObject\MockObject */ |
|||
private $request; |
|||
|
|||
public function setUp(): void { |
|||
$this->plugin = new ViewOnlyPlugin( |
|||
$this->createMock(ILogger::class) |
|||
); |
|||
$this->request = $this->createMock(RequestInterface::class); |
|||
$this->tree = $this->createMock(Tree::class); |
|||
|
|||
$server = $this->createMock(Server::class); |
|||
$server->tree = $this->tree; |
|||
|
|||
$this->plugin->initialize($server); |
|||
} |
|||
|
|||
public function testCanGetNonDav() { |
|||
$this->request->expects($this->once())->method('getPath')->willReturn('files/test/target'); |
|||
$this->tree->method('getNodeForPath')->willReturn(null); |
|||
|
|||
$this->assertTrue($this->plugin->checkViewOnly($this->request)); |
|||
} |
|||
|
|||
public function testCanGetNonShared() { |
|||
$this->request->expects($this->once())->method('getPath')->willReturn('files/test/target'); |
|||
$davNode = $this->createMock(DavFile::class); |
|||
$this->tree->method('getNodeForPath')->willReturn($davNode); |
|||
|
|||
$file = $this->createMock(File::class); |
|||
$davNode->method('getNode')->willReturn($file); |
|||
|
|||
$storage = $this->createMock(IStorage::class); |
|||
$file->method('getStorage')->willReturn($storage); |
|||
$storage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); |
|||
|
|||
$this->assertTrue($this->plugin->checkViewOnly($this->request)); |
|||
} |
|||
|
|||
public function providesDataForCanGet() { |
|||
return [ |
|||
// has attribute permissions-download enabled - can get file
|
|||
[ $this->createMock(File::class), true, true], |
|||
// has no attribute permissions-download - can get file
|
|||
[ $this->createMock(File::class), null, true], |
|||
// has attribute permissions-download disabled- cannot get the file
|
|||
[ $this->createMock(File::class), false, false], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider providesDataForCanGet |
|||
*/ |
|||
public function testCanGet($nodeInfo, $attrEnabled, $expectCanDownloadFile) { |
|||
$this->request->expects($this->once())->method('getPath')->willReturn('files/test/target'); |
|||
|
|||
$davNode = $this->createMock(DavFile::class); |
|||
$this->tree->method('getNodeForPath')->willReturn($davNode); |
|||
|
|||
$davNode->method('getNode')->willReturn($nodeInfo); |
|||
|
|||
$storage = $this->createMock(SharedStorage::class); |
|||
$share = $this->createMock(IShare::class); |
|||
$nodeInfo->method('getStorage')->willReturn($storage); |
|||
$storage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); |
|||
$storage->method('getShare')->willReturn($share); |
|||
|
|||
$extAttr = $this->createMock(IAttributes::class); |
|||
$share->method('getAttributes')->willReturn($extAttr); |
|||
$extAttr->method('getAttribute')->with('permissions', 'download')->willReturn($attrEnabled); |
|||
|
|||
if (!$expectCanDownloadFile) { |
|||
$this->expectException(Forbidden::class); |
|||
} |
|||
$this->plugin->checkViewOnly($this->request); |
|||
} |
|||
} |
@ -0,0 +1,116 @@ |
|||
<?php |
|||
/** |
|||
* @author Piotr Mrowczynski piotr@owncloud.com |
|||
* |
|||
* @copyright Copyright (c) 2019, ownCloud GmbH |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Files_Sharing; |
|||
|
|||
use OCP\Files\File; |
|||
use OCP\Files\Folder; |
|||
use OCP\Files\Node; |
|||
use OCP\Files\NotFoundException; |
|||
|
|||
/** |
|||
* Handles restricting for download of files |
|||
*/ |
|||
class ViewOnly { |
|||
|
|||
/** @var Folder */ |
|||
private $userFolder; |
|||
|
|||
public function __construct(Folder $userFolder) { |
|||
$this->userFolder = $userFolder; |
|||
} |
|||
|
|||
/** |
|||
* @param string[] $pathsToCheck |
|||
* @return bool |
|||
*/ |
|||
public function check($pathsToCheck) { |
|||
// If any of elements cannot be downloaded, prevent whole download
|
|||
foreach ($pathsToCheck as $file) { |
|||
try { |
|||
$info = $this->userFolder->get($file); |
|||
if ($info instanceof File) { |
|||
// access to filecache is expensive in the loop
|
|||
if (!$this->checkFileInfo($info)) { |
|||
return false; |
|||
} |
|||
} elseif ($info instanceof Folder) { |
|||
// get directory content is rather cheap query
|
|||
if (!$this->dirRecursiveCheck($info)) { |
|||
return false; |
|||
} |
|||
} |
|||
} catch (NotFoundException $e) { |
|||
continue; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @param Folder $dirInfo |
|||
* @return bool |
|||
* @throws NotFoundException |
|||
*/ |
|||
private function dirRecursiveCheck(Folder $dirInfo) { |
|||
if (!$this->checkFileInfo($dirInfo)) { |
|||
return false; |
|||
} |
|||
// If any of elements cannot be downloaded, prevent whole download
|
|||
$files = $dirInfo->getDirectoryListing(); |
|||
foreach ($files as $file) { |
|||
if ($file instanceof File) { |
|||
if (!$this->checkFileInfo($file)) { |
|||
return false; |
|||
} |
|||
} elseif ($file instanceof Folder) { |
|||
return $this->dirRecursiveCheck($file); |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @param Node $fileInfo |
|||
* @return bool |
|||
* @throws NotFoundException |
|||
*/ |
|||
private function checkFileInfo(Node $fileInfo) { |
|||
// Restrict view-only to nodes which are shared
|
|||
$storage = $fileInfo->getStorage(); |
|||
if (!$storage->instanceOfStorage(SharedStorage::class)) { |
|||
return true; |
|||
} |
|||
|
|||
// Extract extra permissions
|
|||
/** @var \OCA\Files_Sharing\SharedStorage $storage */ |
|||
$share = $storage->getShare(); |
|||
|
|||
// Check if read-only and on whether permission can download is both set and disabled.
|
|||
|
|||
$canDownload = $share->getAttributes()->getAttribute('permissions', 'download'); |
|||
if ($canDownload !== null && !$canDownload) { |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
} |
@ -0,0 +1,238 @@ |
|||
<?php |
|||
/** |
|||
* @copyright 2022, Vincent Petry <vincent@nextcloud.com> |
|||
* |
|||
* @author Vincent Petry <vincent@nextcloud.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\Tests; |
|||
|
|||
use Psr\Log\LoggerInterface; |
|||
use OC\Share20\LegacyHooks; |
|||
use OC\Share20\Manager; |
|||
use OC\EventDispatcher\EventDispatcher; |
|||
use OCA\Files_Sharing\AppInfo\Application; |
|||
use OCA\Files_Sharing\SharedStorage; |
|||
use OCP\Constants; |
|||
use OCP\EventDispatcher\GenericEvent; |
|||
use OCP\EventDispatcher\IEventDispatcher; |
|||
use OCP\Files\Cache\ICacheEntry; |
|||
use OCP\Files\File; |
|||
use OCP\Files\Folder; |
|||
use OCP\Files\IRootFolder; |
|||
use OCP\Files\Storage\IStorage; |
|||
use OCP\IServerContainer; |
|||
use OCP\IUser; |
|||
use OCP\IUserSession; |
|||
use OCP\Share\IAttributes; |
|||
use OCP\Share\IShare; |
|||
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher; |
|||
use Test\TestCase; |
|||
|
|||
class ApplicationTest extends TestCase { |
|||
|
|||
/** @var Application */ |
|||
private $application; |
|||
|
|||
/** @var IEventDispatcher */ |
|||
private $eventDispatcher; |
|||
|
|||
/** @var IUserSession */ |
|||
private $userSession; |
|||
|
|||
/** @var IRootFolder */ |
|||
private $rootFolder; |
|||
|
|||
/** @var Manager */ private $manager; |
|||
|
|||
protected function setUp(): void { |
|||
parent::setUp(); |
|||
|
|||
$this->application = new Application([]); |
|||
|
|||
// FIXME: how to mock this one ??
|
|||
$symfonyDispatcher = $this->createMock(SymfonyDispatcher::class); |
|||
$this->eventDispatcher = new EventDispatcher( |
|||
$symfonyDispatcher, |
|||
$this->createMock(IServerContainer::class), |
|||
$this->createMock(LoggerInterface::class) |
|||
); |
|||
$this->userSession = $this->createMock(IUserSession::class); |
|||
$this->rootFolder = $this->createMock(IRootFolder::class); |
|||
|
|||
$this->application->registerDownloadEvents( |
|||
$this->eventDispatcher, |
|||
$this->userSession, |
|||
$this->rootFolder |
|||
); |
|||
} |
|||
|
|||
public function providesDataForCanGet() { |
|||
// normal file (sender) - can download directly
|
|||
$senderFileStorage = $this->createMock(IStorage::class); |
|||
$senderFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); |
|||
$senderFile = $this->createMock(File::class); |
|||
$senderFile->method('getStorage')->willReturn($senderFileStorage); |
|||
$senderUserFolder = $this->createMock(Folder::class); |
|||
$senderUserFolder->method('get')->willReturn($senderFile); |
|||
|
|||
$result[] = [ '/bar.txt', $senderUserFolder, true ]; |
|||
|
|||
// shared file (receiver) with attribute secure-view-enabled set false -
|
|||
// can download directly
|
|||
$receiverFileShareAttributes = $this->createMock(IAttributes::class); |
|||
$receiverFileShareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true); |
|||
$receiverFileShare = $this->createMock(IShare::class); |
|||
$receiverFileShare->method('getAttributes')->willReturn($receiverFileShareAttributes); |
|||
$receiverFileStorage = $this->createMock(SharedStorage::class); |
|||
$receiverFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); |
|||
$receiverFileStorage->method('getShare')->willReturn($receiverFileShare); |
|||
$receiverFile = $this->createMock(File::class); |
|||
$receiverFile->method('getStorage')->willReturn($receiverFileStorage); |
|||
$receiverUserFolder = $this->createMock(Folder::class); |
|||
$receiverUserFolder->method('get')->willReturn($receiverFile); |
|||
|
|||
$result[] = [ '/share-bar.txt', $receiverUserFolder, true ]; |
|||
|
|||
// shared file (receiver) with attribute secure-view-enabled set true -
|
|||
// cannot download directly
|
|||
$secureReceiverFileShareAttributes = $this->createMock(IAttributes::class); |
|||
$secureReceiverFileShareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(false); |
|||
$secureReceiverFileShare = $this->createMock(IShare::class); |
|||
$secureReceiverFileShare->method('getAttributes')->willReturn($secureReceiverFileShareAttributes); |
|||
$secureReceiverFileStorage = $this->createMock(SharedStorage::class); |
|||
$secureReceiverFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); |
|||
$secureReceiverFileStorage->method('getShare')->willReturn($secureReceiverFileShare); |
|||
$secureReceiverFile = $this->createMock(File::class); |
|||
$secureReceiverFile->method('getStorage')->willReturn($secureReceiverFileStorage); |
|||
$secureReceiverUserFolder = $this->createMock(Folder::class); |
|||
$secureReceiverUserFolder->method('get')->willReturn($secureReceiverFile); |
|||
|
|||
$result[] = [ '/secure-share-bar.txt', $secureReceiverUserFolder, false ]; |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider providesDataForCanGet |
|||
*/ |
|||
public function testCheckDirectCanBeDownloaded($path, $userFolder, $run) { |
|||
$user = $this->createMock(IUser::class); |
|||
$user->method("getUID")->willReturn("test"); |
|||
$this->userSession->method("getUser")->willReturn($user); |
|||
$this->userSession->method("isLoggedIn")->willReturn(true); |
|||
$this->rootFolder->method('getUserFolder')->willReturn($userFolder); |
|||
|
|||
// Simulate direct download of file
|
|||
$event = new GenericEvent(null, [ 'path' => $path ]); |
|||
$this->eventDispatcher->dispatch('file.beforeGetDirect', $event); |
|||
|
|||
$this->assertEquals($run, !$event->hasArgument('errorMessage')); |
|||
} |
|||
|
|||
public function providesDataForCanZip() { |
|||
// Mock: Normal file/folder storage
|
|||
$nonSharedStorage = $this->createMock(IStorage::class); |
|||
$nonSharedStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); |
|||
|
|||
// Mock: Secure-view file/folder shared storage
|
|||
$secureReceiverFileShareAttributes = $this->createMock(IAttributes::class); |
|||
$secureReceiverFileShareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(false); |
|||
$secureReceiverFileShare = $this->createMock(IShare::class); |
|||
$secureReceiverFileShare->method('getAttributes')->willReturn($secureReceiverFileShareAttributes); |
|||
$secureSharedStorage = $this->createMock(SharedStorage::class); |
|||
$secureSharedStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); |
|||
$secureSharedStorage->method('getShare')->willReturn($secureReceiverFileShare); |
|||
|
|||
// 1. can download zipped 2 non-shared files inside non-shared folder
|
|||
// 2. can download zipped non-shared folder
|
|||
$sender1File = $this->createMock(File::class); |
|||
$sender1File->method('getStorage')->willReturn($nonSharedStorage); |
|||
$sender1Folder = $this->createMock(Folder::class); |
|||
$sender1Folder->method('getStorage')->willReturn($nonSharedStorage); |
|||
$sender1Folder->method('getDirectoryListing')->willReturn([$sender1File, $sender1File]); |
|||
$sender1RootFolder = $this->createMock(Folder::class); |
|||
$sender1RootFolder->method('getStorage')->willReturn($nonSharedStorage); |
|||
$sender1RootFolder->method('getDirectoryListing')->willReturn([$sender1Folder]); |
|||
$sender1UserFolder = $this->createMock(Folder::class); |
|||
$sender1UserFolder->method('get')->willReturn($sender1RootFolder); |
|||
|
|||
$return[] = [ '/folder', ['bar1.txt', 'bar2.txt'], $sender1UserFolder, true ]; |
|||
$return[] = [ '/', 'folder', $sender1UserFolder, true ]; |
|||
|
|||
// 3. cannot download zipped 1 non-shared file and 1 secure-shared inside non-shared folder
|
|||
$receiver1File = $this->createMock(File::class); |
|||
$receiver1File->method('getStorage')->willReturn($nonSharedStorage); |
|||
$receiver1SecureFile = $this->createMock(File::class); |
|||
$receiver1SecureFile->method('getStorage')->willReturn($secureSharedStorage); |
|||
$receiver1Folder = $this->createMock(Folder::class); |
|||
$receiver1Folder->method('getStorage')->willReturn($nonSharedStorage); |
|||
$receiver1Folder->method('getDirectoryListing')->willReturn([$receiver1File, $receiver1SecureFile]); |
|||
$receiver1RootFolder = $this->createMock(Folder::class); |
|||
$receiver1RootFolder->method('getStorage')->willReturn($nonSharedStorage); |
|||
$receiver1RootFolder->method('getDirectoryListing')->willReturn([$receiver1Folder]); |
|||
$receiver1UserFolder = $this->createMock(Folder::class); |
|||
$receiver1UserFolder->method('get')->willReturn($receiver1RootFolder); |
|||
|
|||
$return[] = [ '/folder', ['secured-bar1.txt', 'bar2.txt'], $receiver1UserFolder, false ]; |
|||
|
|||
// 4. cannot download zipped secure-shared folder
|
|||
$receiver2Folder = $this->createMock(Folder::class); |
|||
$receiver2Folder->method('getStorage')->willReturn($secureSharedStorage); |
|||
$receiver2RootFolder = $this->createMock(Folder::class); |
|||
$receiver2RootFolder->method('getStorage')->willReturn($nonSharedStorage); |
|||
$receiver2RootFolder->method('getDirectoryListing')->willReturn([$receiver2Folder]); |
|||
$receiver2UserFolder = $this->createMock(Folder::class); |
|||
$receiver2UserFolder->method('get')->willReturn($receiver2RootFolder); |
|||
|
|||
$return[] = [ '/', 'secured-folder', $receiver2UserFolder, false ]; |
|||
|
|||
return $return; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider providesDataForCanZip |
|||
*/ |
|||
public function testCheckZipCanBeDownloaded($dir, $files, $userFolder, $run) { |
|||
$user = $this->createMock(IUser::class); |
|||
$user->method("getUID")->willReturn("test"); |
|||
$this->userSession->method("getUser")->willReturn($user); |
|||
$this->userSession->method("isLoggedIn")->willReturn(true); |
|||
|
|||
$this->rootFolder->method('getUserFolder')->with("test")->willReturn($userFolder); |
|||
|
|||
// Simulate zip download of folder folder
|
|||
$event = new GenericEvent(null, ['dir' => $dir, 'files' => $files, 'run' => true]); |
|||
$this->eventDispatcher->dispatch('file.beforeCreateZip', $event); |
|||
|
|||
$this->assertEquals($run, $event->getArgument('run')); |
|||
$this->assertEquals($run, !$event->hasArgument('errorMessage')); |
|||
} |
|||
|
|||
public function testCheckFileUserNotFound() { |
|||
$this->userSession->method("isLoggedIn")->willReturn(false); |
|||
|
|||
// Simulate zip download of folder folder
|
|||
$event = new GenericEvent(null, ['dir' => '/test', 'files' => ['test.txt'], 'run' => true]); |
|||
$this->eventDispatcher->dispatch('file.beforeCreateZip', $event); |
|||
|
|||
// It should run as this would restrict e.g. share links otherwise
|
|||
$this->assertTrue($event->getArgument('run')); |
|||
$this->assertFalse($event->hasArgument('errorMessage')); |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
<?php |
|||
/** |
|||
* @author Piotr Mrowczynski <piotr@owncloud.com> |
|||
* |
|||
* @copyright Copyright (c) 2019, ownCloud GmbH |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
namespace OC\Share20; |
|||
|
|||
use OCP\Share\IAttributes; |
|||
|
|||
class ShareAttributes implements IAttributes { |
|||
|
|||
/** @var array */ |
|||
private $attributes; |
|||
|
|||
public function __construct() { |
|||
$this->attributes = []; |
|||
} |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
*/ |
|||
public function setAttribute($scope, $key, $enabled) { |
|||
if (!\array_key_exists($scope, $this->attributes)) { |
|||
$this->attributes[$scope] = []; |
|||
} |
|||
$this->attributes[$scope][$key] = $enabled; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
*/ |
|||
public function getAttribute($scope, $key) { |
|||
if (\array_key_exists($scope, $this->attributes) && |
|||
\array_key_exists($key, $this->attributes[$scope])) { |
|||
return $this->attributes[$scope][$key]; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
*/ |
|||
public function toArray() { |
|||
$result = []; |
|||
foreach ($this->attributes as $scope => $keys) { |
|||
foreach ($keys as $key => $enabled) { |
|||
$result[] = [ |
|||
"scope" => $scope, |
|||
"key" => $key, |
|||
"enabled" => $enabled |
|||
]; |
|||
} |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,68 @@ |
|||
<?php |
|||
/** |
|||
* @author Piotr Mrowczynski <piotr@owncloud.com> |
|||
* |
|||
* @copyright Copyright (c) 2019, ownCloud GmbH |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
namespace OCP\Share; |
|||
|
|||
/** |
|||
* Interface IAttributes |
|||
* |
|||
* @package OCP\Share |
|||
* @since 10.2.0 |
|||
*/ |
|||
interface IAttributes { |
|||
|
|||
/** |
|||
* Sets an attribute enabled/disabled. If the key did not exist before it will be created. |
|||
* |
|||
* @param string $scope scope |
|||
* @param string $key key |
|||
* @param bool $enabled enabled |
|||
* @return IAttributes The modified object |
|||
* @since 10.2.0 |
|||
*/ |
|||
public function setAttribute($scope, $key, $enabled); |
|||
|
|||
/** |
|||
* Returns if attribute is enabled/disabled for given scope id and key. |
|||
* If attribute does not exist, returns null |
|||
* |
|||
* @param string $scope scope |
|||
* @param string $key key |
|||
* @return bool|null |
|||
* @since 10.2.0 |
|||
*/ |
|||
public function getAttribute($scope, $key); |
|||
|
|||
/** |
|||
* Formats the IAttributes object to array with the following format: |
|||
* [ |
|||
* 0 => [ |
|||
* "scope" => <string>, |
|||
* "key" => <string>, |
|||
* "enabled" => <bool> |
|||
* ], |
|||
* ... |
|||
* ] |
|||
* |
|||
* @return array formatted IAttributes |
|||
* @since 10.2.0 |
|||
*/ |
|||
public function toArray(); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue