aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/tests/Controller/ShareControllerTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_sharing/tests/Controller/ShareControllerTest.php')
-rw-r--r--apps/files_sharing/tests/Controller/ShareControllerTest.php863
1 files changed, 587 insertions, 276 deletions
diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php
index 6062ff89065..011210aff42 100644
--- a/apps/files_sharing/tests/Controller/ShareControllerTest.php
+++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php
@@ -1,56 +1,52 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Cloutier <vincent1cloutier@gmail.com>
- *
- * @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/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Files_Sharing\Tests\Controllers;
use OC\Files\Filesystem;
+use OC\Files\Node\Folder;
+use OC\Share20\Manager;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\Files_Sharing\Controller\ShareController;
+use OCA\Files_Sharing\DefaultPublicShareTemplateProvider;
+use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
+use OCP\Accounts\IAccount;
+use OCP\Accounts\IAccountManager;
+use OCP\Accounts\IAccountProperty;
+use OCP\Activity\IManager;
+use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\Template\ExternalShareMenuAction;
+use OCP\AppFramework\Http\Template\LinkMenuAction;
+use OCP\AppFramework\Http\Template\PublicTemplateResponse;
+use OCP\AppFramework\Http\Template\SimpleMenuAction;
+use OCP\AppFramework\Services\IInitialState;
+use OCP\Constants;
+use OCP\Defaults;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\File;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IL10N;
-use OCP\ILogger;
use OCP\IPreview;
use OCP\IRequest;
-use OCP\IUser;
-use OCP\Share\Exceptions\ShareNotFound;
-use OCP\AppFramework\Http\NotFoundResponse;
-use OCP\AppFramework\Http\RedirectResponse;
-use OCP\AppFramework\Http\TemplateResponse;
use OCP\ISession;
+use OCP\IURLGenerator;
+use OCP\IUser;
use OCP\IUserManager;
use OCP\Security\ISecureRandom;
-use OCP\IURLGenerator;
+use OCP\Server;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\IAttributes;
+use OCP\Share\IPublicShareTemplateFactory;
use OCP\Share\IShare;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use PHPUnit\Framework\MockObject\MockObject;
/**
* @group DB
@@ -59,66 +55,88 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
*/
class ShareControllerTest extends \Test\TestCase {
- /** @var string */
- private $user;
- /** @var string */
- private $oldUser;
-
- /** @var string */
- private $appName = 'files_sharing';
- /** @var ShareController */
- private $shareController;
- /** @var IURLGenerator | \PHPUnit_Framework_MockObject_MockObject */
- private $urlGenerator;
- /** @var ISession | \PHPUnit_Framework_MockObject_MockObject */
- private $session;
- /** @var \OCP\IPreview | \PHPUnit_Framework_MockObject_MockObject */
- private $previewManager;
- /** @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject */
- private $config;
- /** @var \OC\Share20\Manager | \PHPUnit_Framework_MockObject_MockObject */
- private $shareManager;
- /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
- private $userManager;
- /** @var FederatedShareProvider | \PHPUnit_Framework_MockObject_MockObject */
- private $federatedShareProvider;
- /** @var EventDispatcherInterface | \PHPUnit_Framework_MockObject_MockObject */
- private $eventDispatcher;
-
- protected function setUp() {
+ private string $user;
+ private string $oldUser;
+ private string $appName = 'files_sharing';
+ private ShareController $shareController;
+
+ private IL10N&MockObject $l10n;
+ private IConfig&MockObject $config;
+ private ISession&MockObject $session;
+ private Defaults&MockObject $defaults;
+ private IAppConfig&MockObject $appConfig;
+ private Manager&MockObject $shareManager;
+ private IPreview&MockObject $previewManager;
+ private IUserManager&MockObject $userManager;
+ private IInitialState&MockObject $initialState;
+ private IURLGenerator&MockObject $urlGenerator;
+ private ISecureRandom&MockObject $secureRandom;
+ private IAccountManager&MockObject $accountManager;
+ private IEventDispatcher&MockObject $eventDispatcher;
+ private FederatedShareProvider&MockObject $federatedShareProvider;
+ private IPublicShareTemplateFactory&MockObject $publicShareTemplateFactory;
+
+ protected function setUp(): void {
parent::setUp();
$this->appName = 'files_sharing';
- $this->shareManager = $this->getMockBuilder('\OC\Share20\Manager')->disableOriginalConstructor()->getMock();
- $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock();
- $this->session = $this->getMockBuilder(ISession::class)->getMock();
- $this->previewManager = $this->getMockBuilder(IPreview::class)->getMock();
- $this->config = $this->getMockBuilder(IConfig::class)->getMock();
- $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock();
- $this->federatedShareProvider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider')
- ->disableOriginalConstructor()->getMock();
+ $this->shareManager = $this->createMock(Manager::class);
+ $this->urlGenerator = $this->createMock(IURLGenerator::class);
+ $this->session = $this->createMock(ISession::class);
+ $this->previewManager = $this->createMock(IPreview::class);
+ $this->config = $this->createMock(IConfig::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->initialState = $this->createMock(IInitialState::class);
+ $this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
$this->federatedShareProvider->expects($this->any())
->method('isOutgoingServer2serverShareEnabled')->willReturn(true);
$this->federatedShareProvider->expects($this->any())
->method('isIncomingServer2serverShareEnabled')->willReturn(true);
- $this->eventDispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
+ $this->accountManager = $this->createMock(IAccountManager::class);
+ $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
+ $this->l10n = $this->createMock(IL10N::class);
+ $this->secureRandom = $this->createMock(ISecureRandom::class);
+ $this->defaults = $this->createMock(Defaults::class);
+ $this->publicShareTemplateFactory = $this->createMock(IPublicShareTemplateFactory::class);
+ $this->publicShareTemplateFactory
+ ->expects($this->any())
+ ->method('getProvider')
+ ->willReturn(
+ new DefaultPublicShareTemplateProvider(
+ $this->userManager,
+ $this->accountManager,
+ $this->previewManager,
+ $this->federatedShareProvider,
+ $this->urlGenerator,
+ $this->eventDispatcher,
+ $this->l10n,
+ $this->defaults,
+ $this->config,
+ $this->createMock(IRequest::class),
+ $this->initialState,
+ $this->appConfig,
+ )
+ );
- $this->shareController = new \OCA\Files_Sharing\Controller\ShareController(
+ $this->shareController = new ShareController(
$this->appName,
- $this->getMockBuilder(IRequest::class)->getMock(),
+ $this->createMock(IRequest::class),
$this->config,
$this->urlGenerator,
$this->userManager,
- $this->getMockBuilder(ILogger::class)->getMock(),
- $this->getMockBuilder('\OCP\Activity\IManager')->getMock(),
+ $this->createMock(IManager::class),
$this->shareManager,
$this->session,
$this->previewManager,
- $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(),
+ $this->createMock(IRootFolder::class),
$this->federatedShareProvider,
+ $this->accountManager,
$this->eventDispatcher,
- $this->getMockBuilder(IL10N::class)->getMock(),
- $this->getMockBuilder('\OCP\Defaults')->getMock()
+ $this->l10n,
+ $this->secureRandom,
+ $this->defaults,
+ $this->publicShareTemplateFactory,
);
@@ -126,22 +144,24 @@ class ShareControllerTest extends \Test\TestCase {
$this->oldUser = \OC_User::getUser();
// Create a dummy user
- $this->user = \OC::$server->getSecureRandom()->generate(12, ISecureRandom::CHAR_LOWER);
+ $this->user = Server::get(ISecureRandom::class)->generate(12, ISecureRandom::CHAR_LOWER);
- \OC::$server->getUserManager()->createUser($this->user, $this->user);
+ Server::get(IUserManager::class)->createUser($this->user, $this->user);
\OC_Util::tearDownFS();
$this->loginAsUser($this->user);
}
- protected function tearDown() {
+ protected function tearDown(): void {
\OC_Util::tearDownFS();
\OC_User::setUserId('');
Filesystem::tearDown();
- $user = \OC::$server->getUserManager()->get($this->user);
- if ($user !== null) { $user->delete(); }
+ $user = Server::get(IUserManager::class)->get($this->user);
+ if ($user !== null) {
+ $user->delete();
+ }
\OC_User::setIncognitoMode(false);
- \OC::$server->getSession()->set('public_link_authenticated', '');
+ Server::get(ISession::class)->set('public_link_authenticated', '');
// Set old user
\OC_User::setUserId($this->oldUser);
@@ -149,76 +169,118 @@ class ShareControllerTest extends \Test\TestCase {
parent::tearDown();
}
- public function testShowAuthenticateNotAuthenticated() {
- $share = \OC::$server->getShareManager()->newShare();
+ public function testShowShareInvalidToken(): void {
+ $this->shareController->setToken('invalidtoken');
$this->shareManager
->expects($this->once())
->method('getShareByToken')
- ->with('token')
- ->willReturn($share);
+ ->with('invalidtoken')
+ ->willThrowException(new ShareNotFound());
- $response = $this->shareController->showAuthenticate('token');
- $expectedResponse = new TemplateResponse($this->appName, 'authenticate', [], 'guest');
- $this->assertEquals($expectedResponse, $response);
+ $this->expectException(NotFoundException::class);
+
+ // Test without a not existing token
+ $this->shareController->showShare();
}
- public function testShowAuthenticateAuthenticatedForDifferentShare() {
- $share = \OC::$server->getShareManager()->newShare();
- $share->setId(1);
+ public function testShowShareNotAuthenticated(): void {
+ $this->shareController->setToken('validtoken');
+
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setPassword('password');
$this->shareManager
->expects($this->once())
->method('getShareByToken')
- ->with('token')
+ ->with('validtoken')
->willReturn($share);
- $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
- $this->session->method('get')->with('public_link_authenticated')->willReturn('2');
+ $this->expectException(NotFoundException::class);
- $response = $this->shareController->showAuthenticate('token');
- $expectedResponse = new TemplateResponse($this->appName, 'authenticate', [], 'guest');
- $this->assertEquals($expectedResponse, $response);
+ // Test without a not existing token
+ $this->shareController->showShare();
}
- public function testShowAuthenticateCorrectShare() {
- $share = \OC::$server->getShareManager()->newShare();
- $share->setId(1);
- $this->shareManager
- ->expects($this->once())
- ->method('getShareByToken')
- ->with('token')
- ->willReturn($share);
+ public function testShowShare(): void {
+ $note = 'personal note';
+ $filename = 'file1.txt';
- $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
- $this->session->method('get')->with('public_link_authenticated')->willReturn('1');
+ $this->shareController->setToken('token');
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('files_sharing.sharecontroller.showShare', ['token' => 'token'])
- ->willReturn('redirect');
+ $owner = $this->createMock(IUser::class);
+ $owner->method('getDisplayName')->willReturn('ownerDisplay');
+ $owner->method('getUID')->willReturn('ownerUID');
+ $owner->method('isEnabled')->willReturn(true);
- $response = $this->shareController->showAuthenticate('token');
- $expectedResponse = new RedirectResponse('redirect');
- $this->assertEquals($expectedResponse, $response);
- }
+ $initiator = $this->createMock(IUser::class);
+ $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
+ $initiator->method('getUID')->willReturn('initiatorUID');
+ $initiator->method('isEnabled')->willReturn(true);
- public function testAuthenticateInvalidToken() {
- $this->shareManager
- ->expects($this->once())
- ->method('getShareByToken')
- ->with('token')
- ->will($this->throwException(new \OCP\Share\Exceptions\ShareNotFound()));
+ $file = $this->createMock(File::class);
+ $file->method('getName')->willReturn($filename);
+ $file->method('getMimetype')->willReturn('text/plain');
+ $file->method('getSize')->willReturn(33);
+ $file->method('isReadable')->willReturn(true);
+ $file->method('isShareable')->willReturn(true);
+ $file->method('getId')->willReturn(111);
+
+ $accountName = $this->createMock(IAccountProperty::class);
+ $accountName->method('getScope')
+ ->willReturn(IAccountManager::SCOPE_PUBLISHED);
+ $account = $this->createMock(IAccount::class);
+ $account->method('getProperty')
+ ->with(IAccountManager::PROPERTY_DISPLAYNAME)
+ ->willReturn($accountName);
+ $this->accountManager->expects($this->once())
+ ->method('getAccount')
+ ->with($owner)
+ ->willReturn($account);
+
+ /** @var Manager */
+ $manager = Server::get(Manager::class);
+ $share = $manager->newShare();
+ $share->setId(42)
+ ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE)
+ ->setPassword('password')
+ ->setShareOwner('ownerUID')
+ ->setSharedBy('initiatorUID')
+ ->setNode($file)
+ ->setNote($note)
+ ->setTarget("/$filename")
+ ->setToken('token');
- $response = $this->shareController->authenticate('token');
- $expectedResponse = new NotFoundResponse();
- $this->assertEquals($expectedResponse, $response);
- }
+ $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
+ $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
- public function testAuthenticateValidPassword() {
- $share = \OC::$server->getShareManager()->newShare();
- $share->setId(42);
+ $this->urlGenerator->expects(self::atLeast(2))
+ ->method('linkToRouteAbsolute')
+ ->willReturnMap([
+ // every file has the show show share url in the opengraph url prop
+ ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'],
+ // this share is not an image to the default preview is used
+ ['files_sharing.PublicPreview.getPreview', ['x' => 256, 'y' => 256, 'file' => $share->getTarget(), 'token' => 'token'], 'previewUrl'],
+ ]);
+
+ $this->urlGenerator->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->willReturnMap([
+ ['/public.php/dav/files/token/?accept=zip', 'downloadUrl'],
+ ]);
+
+ $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
+
+ $this->config->method('getSystemValue')
+ ->willReturnMap(
+ [
+ ['max_filesize_animated_gifs_public_sharing', 10, 10],
+ ['enable_previews', true, true],
+ ['preview_max_x', 1024, 1024],
+ ['preview_max_y', 1024, 1024],
+ ]
+ );
$this->shareManager
->expects($this->once())
@@ -226,128 +288,289 @@ class ShareControllerTest extends \Test\TestCase {
->with('token')
->willReturn($share);
- $this->shareManager
- ->expects($this->once())
- ->method('checkPassword')
- ->with($share, 'validpassword')
- ->willReturn(true);
+ $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
+ if ($uid === 'ownerUID') {
+ return $owner;
+ }
+ if ($uid === 'initiatorUID') {
+ return $initiator;
+ }
+ return null;
+ });
+
+ $this->eventDispatcher->method('dispatchTyped')->with(
+ $this->callback(function ($event) use ($share) {
+ if ($event instanceof BeforeTemplateRenderedEvent) {
+ return $event->getShare() === $share;
+ } else {
+ return true;
+ }
+ })
+ );
- $this->session
- ->expects($this->once())
- ->method('set')
- ->with('public_link_authenticated', '42');
+ $this->l10n->expects($this->any())
+ ->method('t')
+ ->willReturnCallback(function ($text, $parameters) {
+ return vsprintf($text, $parameters);
+ });
+
+ $this->defaults->expects(self::any())
+ ->method('getProductName')
+ ->willReturn('Nextcloud');
+
+ // Ensure the correct initial state is setup
+ // Shared node is a file so this is a single file share:
+ $view = 'public-file-share';
+ // Set up initial state
+ $initialState = [];
+ $this->initialState->expects(self::any())
+ ->method('provideInitialState')
+ ->willReturnCallback(function ($key, $value) use (&$initialState): void {
+ $initialState[$key] = $value;
+ });
+ $expectedInitialState = [
+ 'isPublic' => true,
+ 'sharingToken' => 'token',
+ 'sharePermissions' => (Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE),
+ 'filename' => $filename,
+ 'view' => $view,
+ 'fileId' => 111,
+ 'owner' => 'ownerUID',
+ 'ownerDisplayName' => 'ownerDisplay',
+ 'isFileRequest' => false,
+ ];
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('files_sharing.sharecontroller.showShare', ['token'=>'token'])
- ->willReturn('redirect');
+ $response = $this->shareController->showShare();
+
+ $this->assertEquals($expectedInitialState, $initialState);
+
+ $csp = new ContentSecurityPolicy();
+ $csp->addAllowedFrameDomain('\'self\'');
+ $expectedResponse = new PublicTemplateResponse('files', 'index');
+ $expectedResponse->setParams(['pageTitle' => $filename]);
+ $expectedResponse->setContentSecurityPolicy($csp);
+ $expectedResponse->setHeaderTitle($filename);
+ $expectedResponse->setHeaderDetails('shared by ownerDisplay');
+ $expectedResponse->setHeaderActions([
+ new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', 'downloadUrl', 0, '33'),
+ new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', 'owner', 'ownerDisplay', $filename),
+ new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'downloadUrl'),
+ ]);
- $response = $this->shareController->authenticate('token', 'validpassword');
- $expectedResponse = new RedirectResponse('redirect');
$this->assertEquals($expectedResponse, $response);
}
- public function testAuthenticateInvalidPassword() {
- $share = \OC::$server->getShareManager()->newShare();
- $share->setNodeId(100)
- ->setNodeType('file')
- ->setToken('token')
- ->setSharedBy('initiator')
- ->setId(42);
+ public function testShowFileDropShare(): void {
+ $filename = 'folder1';
- $this->shareManager
- ->expects($this->once())
- ->method('getShareByToken')
- ->with('token')
- ->willReturn($share);
+ $this->shareController->setToken('token');
- $this->shareManager
- ->expects($this->once())
- ->method('checkPassword')
- ->with($share, 'invalidpassword')
- ->willReturn(false);
+ $owner = $this->createMock(IUser::class);
+ $owner->method('getDisplayName')->willReturn('ownerDisplay');
+ $owner->method('getUID')->willReturn('ownerUID');
+ $owner->method('isEnabled')->willReturn(true);
- $this->session
- ->expects($this->never())
- ->method('set');
-
- $hookListner = $this->getMockBuilder('Dummy')->setMethods(['access'])->getMock();
- \OCP\Util::connectHook('OCP\Share', 'share_link_access', $hookListner, 'access');
-
- $hookListner->expects($this->once())
- ->method('access')
- ->with($this->callback(function(array $data) {
- return $data['itemType'] === 'file' &&
- $data['itemSource'] === 100 &&
- $data['uidOwner'] === 'initiator' &&
- $data['token'] === 'token' &&
- $data['errorCode'] === 403 &&
- $data['errorMessage'] === 'Wrong password';
- }));
-
- $response = $this->shareController->authenticate('token', 'invalidpassword');
- $expectedResponse = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
- $expectedResponse->throttle();
- $this->assertEquals($expectedResponse, $response);
- }
+ $initiator = $this->createMock(IUser::class);
+ $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
+ $initiator->method('getUID')->willReturn('initiatorUID');
+ $initiator->method('isEnabled')->willReturn(true);
- public function testShowShareInvalidToken() {
- $this->shareManager
+ $file = $this->createMock(Folder::class);
+ $file->method('isReadable')->willReturn(true);
+ $file->method('isShareable')->willReturn(true);
+ $file->method('getId')->willReturn(1234);
+ $file->method('getName')->willReturn($filename);
+
+ $accountName = $this->createMock(IAccountProperty::class);
+ $accountName->method('getScope')
+ ->willReturn(IAccountManager::SCOPE_PUBLISHED);
+ $account = $this->createMock(IAccount::class);
+ $account->method('getProperty')
+ ->with(IAccountManager::PROPERTY_DISPLAYNAME)
+ ->willReturn($accountName);
+ $this->accountManager->expects($this->once())
+ ->method('getAccount')
+ ->with($owner)
+ ->willReturn($account);
+
+ /** @var Manager */
+ $manager = Server::get(Manager::class);
+ $share = $manager->newShare();
+ $share->setId(42)
+ ->setPermissions(Constants::PERMISSION_CREATE)
+ ->setPassword('password')
+ ->setShareOwner('ownerUID')
+ ->setSharedBy('initiatorUID')
+ ->setNote('The note')
+ ->setLabel('A label')
+ ->setNode($file)
+ ->setTarget("/$filename")
+ ->setToken('token');
+
+ $this->appConfig
->expects($this->once())
- ->method('getShareByToken')
- ->with('invalidtoken')
- ->will($this->throwException(new ShareNotFound()));
+ ->method('getValueString')
+ ->with('core', 'shareapi_public_link_disclaimertext', '')
+ ->willReturn('My disclaimer text');
- // Test without a not existing token
- $response = $this->shareController->showShare('invalidtoken');
- $expectedResponse = new NotFoundResponse();
- $this->assertEquals($expectedResponse, $response);
- }
+ $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
+ $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
- public function testShowShareNotAuthenticated() {
- $share = \OC::$server->getShareManager()->newShare();
- $share->setPassword('password');
+ $this->urlGenerator->expects(self::atLeastOnce())
+ ->method('linkToRouteAbsolute')
+ ->willReturnMap([
+ // every file has the show show share url in the opengraph url prop
+ ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'],
+ // there is no preview or folders so no other link for opengraph
+ ]);
+
+ $this->config->method('getSystemValue')
+ ->willReturnMap(
+ [
+ ['max_filesize_animated_gifs_public_sharing', 10, 10],
+ ['enable_previews', true, true],
+ ['preview_max_x', 1024, 1024],
+ ['preview_max_y', 1024, 1024],
+ ]
+ );
$this->shareManager
->expects($this->once())
->method('getShareByToken')
- ->with('validtoken')
+ ->with('token')
->willReturn($share);
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('files_sharing.sharecontroller.authenticate', ['token' => 'validtoken'])
- ->willReturn('redirect');
+ $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
+ if ($uid === 'ownerUID') {
+ return $owner;
+ }
+ if ($uid === 'initiatorUID') {
+ return $initiator;
+ }
+ return null;
+ });
+
+ $this->eventDispatcher->method('dispatchTyped')->with(
+ $this->callback(function ($event) use ($share) {
+ if ($event instanceof BeforeTemplateRenderedEvent) {
+ return $event->getShare() === $share;
+ } else {
+ return true;
+ }
+ })
+ );
+
+ $this->l10n->expects($this->any())
+ ->method('t')
+ ->willReturnCallback(function ($text, $parameters) {
+ return vsprintf($text, $parameters);
+ });
+
+ // Set up initial state
+ $initialState = [];
+ $this->initialState->expects(self::any())
+ ->method('provideInitialState')
+ ->willReturnCallback(function ($key, $value) use (&$initialState): void {
+ $initialState[$key] = $value;
+ });
+ $expectedInitialState = [
+ 'isPublic' => true,
+ 'sharingToken' => 'token',
+ 'sharePermissions' => Constants::PERMISSION_CREATE,
+ 'filename' => $filename,
+ 'view' => 'public-file-drop',
+ 'disclaimer' => 'My disclaimer text',
+ 'owner' => 'ownerUID',
+ 'ownerDisplayName' => 'ownerDisplay',
+ 'isFileRequest' => false,
+ 'note' => 'The note',
+ 'label' => 'A label',
+ ];
+
+ $response = $this->shareController->showShare();
+
+ $this->assertEquals($expectedInitialState, $initialState);
+
+ $csp = new ContentSecurityPolicy();
+ $csp->addAllowedFrameDomain('\'self\'');
+ $expectedResponse = new PublicTemplateResponse('files', 'index');
+ $expectedResponse->setParams(['pageTitle' => 'A label']);
+ $expectedResponse->setContentSecurityPolicy($csp);
+ $expectedResponse->setHeaderTitle('A label');
+ $expectedResponse->setHeaderDetails('shared by ownerDisplay');
+ $expectedResponse->setHeaderActions([
+ new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'shareUrl'),
+ ]);
- // Test without a not existing token
- $response = $this->shareController->showShare('validtoken');
- $expectedResponse = new RedirectResponse('redirect');
$this->assertEquals($expectedResponse, $response);
}
+ public function testShowShareWithPrivateName(): void {
+ $note = 'personal note';
+ $filename = 'file1.txt';
- public function testShowShare() {
- $owner = $this->getMockBuilder(IUser::class)->getMock();
+ $this->shareController->setToken('token');
+
+ $owner = $this->createMock(IUser::class);
$owner->method('getDisplayName')->willReturn('ownerDisplay');
$owner->method('getUID')->willReturn('ownerUID');
+ $owner->method('isEnabled')->willReturn(true);
- $file = $this->getMockBuilder('OCP\Files\File')->getMock();
- $file->method('getName')->willReturn('file1.txt');
+ $initiator = $this->createMock(IUser::class);
+ $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
+ $initiator->method('getUID')->willReturn('initiatorUID');
+ $initiator->method('isEnabled')->willReturn(true);
+
+ $file = $this->createMock(File::class);
+ $file->method('getName')->willReturn($filename);
$file->method('getMimetype')->willReturn('text/plain');
$file->method('getSize')->willReturn(33);
$file->method('isReadable')->willReturn(true);
$file->method('isShareable')->willReturn(true);
-
- $share = \OC::$server->getShareManager()->newShare();
+ $file->method('getId')->willReturn(111);
+
+ $accountName = $this->createMock(IAccountProperty::class);
+ $accountName->method('getScope')
+ ->willReturn(IAccountManager::SCOPE_LOCAL);
+ $account = $this->createMock(IAccount::class);
+ $account->method('getProperty')
+ ->with(IAccountManager::PROPERTY_DISPLAYNAME)
+ ->willReturn($accountName);
+ $this->accountManager->expects($this->once())
+ ->method('getAccount')
+ ->with($owner)
+ ->willReturn($account);
+
+ /** @var IShare */
+ $share = Server::get(Manager::class)->newShare();
$share->setId(42);
$share->setPassword('password')
->setShareOwner('ownerUID')
+ ->setSharedBy('initiatorUID')
->setNode($file)
- ->setTarget('/file1.txt');
+ ->setNote($note)
+ ->setToken('token')
+ ->setPermissions(Constants::PERMISSION_ALL & ~Constants::PERMISSION_SHARE)
+ ->setTarget("/$filename");
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
$this->session->method('get')->with('public_link_authenticated')->willReturn('42');
+ $this->urlGenerator->expects(self::atLeast(2))
+ ->method('linkToRouteAbsolute')
+ ->willReturnMap([
+ // every file has the show show share url in the opengraph url prop
+ ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'],
+ // this share is not an image to the default preview is used
+ ['files_sharing.PublicPreview.getPreview', ['x' => 256, 'y' => 256, 'file' => $share->getTarget(), 'token' => 'token'], 'previewUrl'],
+ ]);
+
+ $this->urlGenerator->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->willReturnMap([
+ ['/public.php/dav/files/token/?accept=zip', 'downloadUrl'],
+ ]);
+
$this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
$this->config->method('getSystemValue')
@@ -367,75 +590,79 @@ class ShareControllerTest extends \Test\TestCase {
->method('getShareByToken')
->with('token')
->willReturn($share);
- $this->config
- ->expects($this->once())
- ->method('getAppValue')
- ->with('core', 'shareapi_public_link_disclaimertext', null)
- ->willReturn('My disclaimer text');
- $this->userManager->method('get')->with('ownerUID')->willReturn($owner);
+ $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
+ if ($uid === 'ownerUID') {
+ return $owner;
+ }
+ if ($uid === 'initiatorUID') {
+ return $initiator;
+ }
+ return null;
+ });
+
+ $this->eventDispatcher->method('dispatchTyped')->with(
+ $this->callback(function ($event) use ($share) {
+ if ($event instanceof BeforeTemplateRenderedEvent) {
+ return $event->getShare() === $share;
+ } else {
+ return true;
+ }
+ })
+ );
- $this->eventDispatcher->expects($this->once())
- ->method('dispatch')
- ->with('OCA\Files_Sharing::loadAdditionalScripts');
+ $this->l10n->expects($this->any())
+ ->method('t')
+ ->willReturnCallback(function ($text, $parameters) {
+ return vsprintf($text, $parameters);
+ });
- $response = $this->shareController->showShare('token');
- $sharedTmplParams = array(
- 'displayName' => 'ownerDisplay',
- 'owner' => 'ownerUID',
- 'filename' => 'file1.txt',
- 'directory_path' => '/file1.txt',
- 'mimetype' => 'text/plain',
- 'dirToken' => 'token',
- 'sharingToken' => 'token',
- 'server2serversharing' => true,
- 'protected' => 'true',
- 'dir' => '',
- 'downloadURL' => null,
- 'fileSize' => '33 B',
- 'nonHumanFileSize' => 33,
- 'maxSizeAnimateGif' => 10,
- 'previewSupported' => true,
- 'previewEnabled' => true,
- 'previewMaxX' => 1024,
- 'previewMaxY' => 1024,
- 'hideFileList' => false,
- 'shareOwner' => 'ownerDisplay',
- 'disclaimer' => 'My disclaimer text',
- 'shareUrl' => null,
- 'previewImage' => null,
- 'previewURL' => null,
- );
+ $this->defaults->expects(self::any())
+ ->method('getProductName')
+ ->willReturn('Nextcloud');
+
+ $response = $this->shareController->showShare();
- $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
+ $csp = new ContentSecurityPolicy();
$csp->addAllowedFrameDomain('\'self\'');
- $expectedResponse = new TemplateResponse($this->appName, 'public', $sharedTmplParams, 'base');
+ $expectedResponse = new PublicTemplateResponse('files', 'index');
+ $expectedResponse->setParams(['pageTitle' => $filename]);
$expectedResponse->setContentSecurityPolicy($csp);
+ $expectedResponse->setHeaderTitle($filename);
+ $expectedResponse->setHeaderDetails('');
+ $expectedResponse->setHeaderActions([
+ new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', 'downloadUrl', 0, '33'),
+ new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', 'owner', 'ownerDisplay', $filename),
+ new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'downloadUrl'),
+ ]);
$this->assertEquals($expectedResponse, $response);
}
- /**
- * @expectedException \OCP\Files\NotFoundException
- */
- public function testShowShareInvalid() {
+
+ public function testShowShareInvalid(): void {
+ $this->expectException(NotFoundException::class);
+
+ $filename = 'file1.txt';
+ $this->shareController->setToken('token');
+
$owner = $this->getMockBuilder(IUser::class)->getMock();
$owner->method('getDisplayName')->willReturn('ownerDisplay');
$owner->method('getUID')->willReturn('ownerUID');
$file = $this->getMockBuilder('OCP\Files\File')->getMock();
- $file->method('getName')->willReturn('file1.txt');
+ $file->method('getName')->willReturn($filename);
$file->method('getMimetype')->willReturn('text/plain');
$file->method('getSize')->willReturn(33);
$file->method('isShareable')->willReturn(false);
$file->method('isReadable')->willReturn(true);
- $share = \OC::$server->getShareManager()->newShare();
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
$share->setId(42);
$share->setPassword('password')
->setShareOwner('ownerUID')
->setNode($file)
- ->setTarget('/file1.txt');
+ ->setTarget("/$filename");
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
$this->session->method('get')->with('public_link_authenticated')->willReturn('42');
@@ -460,16 +687,16 @@ class ShareControllerTest extends \Test\TestCase {
$this->userManager->method('get')->with('ownerUID')->willReturn($owner);
- $this->shareController->showShare('token');
+ $this->shareController->showShare();
}
- public function testDownloadShare() {
+ public function testDownloadShareWithCreateOnlyShare(): void {
$share = $this->getMockBuilder(IShare::class)->getMock();
$share->method('getPassword')->willReturn('password');
$share
->expects($this->once())
->method('getPermissions')
- ->willReturn(\OCP\Constants::PERMISSION_READ);
+ ->willReturn(Constants::PERMISSION_CREATE);
$this->shareManager
->expects($this->once())
@@ -477,35 +704,119 @@ class ShareControllerTest extends \Test\TestCase {
->with('validtoken')
->willReturn($share);
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('files_sharing.sharecontroller.authenticate', ['token' => 'validtoken'])
- ->willReturn('redirect');
-
// Test with a password protected share and no authentication
$response = $this->shareController->downloadShare('validtoken');
- $expectedResponse = new RedirectResponse('redirect');
+ $expectedResponse = new DataResponse('Share has no read permission');
$this->assertEquals($expectedResponse, $response);
}
- public function testDownloadShareWithCreateOnlyShare() {
- $share = $this->getMockBuilder(IShare::class)->getMock();
+ public function testDownloadShareWithoutDownloadPermission(): void {
+ $attributes = $this->createMock(IAttributes::class);
+ $attributes->expects(self::once())
+ ->method('getAttribute')
+ ->with('permissions', 'download')
+ ->willReturn(false);
+
+ $share = $this->createMock(IShare::class);
$share->method('getPassword')->willReturn('password');
- $share
- ->expects($this->once())
+ $share->expects(self::once())
->method('getPermissions')
- ->willReturn(\OCP\Constants::PERMISSION_CREATE);
+ ->willReturn(Constants::PERMISSION_READ);
+ $share->expects(self::once())
+ ->method('getAttributes')
+ ->willReturn($attributes);
$this->shareManager
- ->expects($this->once())
+ ->expects(self::once())
->method('getShareByToken')
->with('validtoken')
->willReturn($share);
// Test with a password protected share and no authentication
$response = $this->shareController->downloadShare('validtoken');
- $expectedResponse = new DataResponse('Share is read-only');
+ $expectedResponse = new DataResponse('Share has no download permission');
$this->assertEquals($expectedResponse, $response);
}
+ public function testDisabledOwner(): void {
+ $this->shareController->setToken('token');
+
+ $owner = $this->getMockBuilder(IUser::class)->getMock();
+ $owner->method('isEnabled')->willReturn(false);
+
+ $initiator = $this->createMock(IUser::class);
+ $initiator->method('isEnabled')->willReturn(false);
+
+ /* @var MockObject|Folder $folder */
+ $folder = $this->createMock(Folder::class);
+
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setId(42);
+ $share->setPermissions(Constants::PERMISSION_CREATE)
+ ->setShareOwner('ownerUID')
+ ->setSharedBy('initiatorUID')
+ ->setNode($folder)
+ ->setTarget('/share');
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
+ if ($uid === 'ownerUID') {
+ return $owner;
+ }
+ if ($uid === 'initiatorUID') {
+ return $initiator;
+ }
+ return null;
+ });
+
+ $this->expectException(NotFoundException::class);
+
+ $this->shareController->showShare();
+ }
+
+ public function testDisabledInitiator(): void {
+ $this->shareController->setToken('token');
+
+ $owner = $this->getMockBuilder(IUser::class)->getMock();
+ $owner->method('isEnabled')->willReturn(false);
+
+ $initiator = $this->createMock(IUser::class);
+ $initiator->method('isEnabled')->willReturn(true);
+
+ /* @var MockObject|Folder $folder */
+ $folder = $this->createMock(Folder::class);
+
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setId(42);
+ $share->setPermissions(Constants::PERMISSION_CREATE)
+ ->setShareOwner('ownerUID')
+ ->setSharedBy('initiatorUID')
+ ->setNode($folder)
+ ->setTarget('/share');
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
+ if ($uid === 'ownerUID') {
+ return $owner;
+ }
+ if ($uid === 'initiatorUID') {
+ return $initiator;
+ }
+ return null;
+ });
+
+ $this->expectException(NotFoundException::class);
+
+ $this->shareController->showShare();
+ }
}