ShareControllerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\Files_Sharing\Tests\Controllers;
  8. use OC\Files\Filesystem;
  9. use OC\Files\Node\Folder;
  10. use OC\Share20\Manager;
  11. use OCA\FederatedFileSharing\FederatedShareProvider;
  12. use OCA\Files_Sharing\Controller\ShareController;
  13. use OCA\Files_Sharing\DefaultPublicShareTemplateProvider;
  14. use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
  15. use OCP\Accounts\IAccount;
  16. use OCP\Accounts\IAccountManager;
  17. use OCP\Accounts\IAccountProperty;
  18. use OCP\Activity\IManager;
  19. use OCP\AppFramework\Http\ContentSecurityPolicy;
  20. use OCP\AppFramework\Http\DataResponse;
  21. use OCP\AppFramework\Http\Template\ExternalShareMenuAction;
  22. use OCP\AppFramework\Http\Template\LinkMenuAction;
  23. use OCP\AppFramework\Http\Template\PublicTemplateResponse;
  24. use OCP\AppFramework\Http\Template\SimpleMenuAction;
  25. use OCP\AppFramework\Services\IInitialState;
  26. use OCP\Constants;
  27. use OCP\Defaults;
  28. use OCP\EventDispatcher\IEventDispatcher;
  29. use OCP\Files\File;
  30. use OCP\Files\IRootFolder;
  31. use OCP\Files\NotFoundException;
  32. use OCP\IAppConfig;
  33. use OCP\IConfig;
  34. use OCP\IL10N;
  35. use OCP\IPreview;
  36. use OCP\IRequest;
  37. use OCP\ISession;
  38. use OCP\IURLGenerator;
  39. use OCP\IUser;
  40. use OCP\IUserManager;
  41. use OCP\Security\ISecureRandom;
  42. use OCP\Server;
  43. use OCP\Share\Exceptions\ShareNotFound;
  44. use OCP\Share\IPublicShareTemplateFactory;
  45. use OCP\Share\IShare;
  46. use PHPUnit\Framework\MockObject\MockObject;
  47. /**
  48. * @group DB
  49. *
  50. * @package OCA\Files_Sharing\Controllers
  51. */
  52. class ShareControllerTest extends \Test\TestCase {
  53. private string $user;
  54. private string $oldUser;
  55. private string $appName = 'files_sharing';
  56. private ShareController $shareController;
  57. private IL10N&MockObject $l10n;
  58. private IConfig&MockObject $config;
  59. private ISession&MockObject $session;
  60. private Defaults&MockObject $defaults;
  61. private IAppConfig&MockObject $appConfig;
  62. private Manager&MockObject $shareManager;
  63. private IPreview&MockObject $previewManager;
  64. private IUserManager&MockObject $userManager;
  65. private IInitialState&MockObject $initialState;
  66. private IURLGenerator&MockObject $urlGenerator;
  67. private ISecureRandom&MockObject $secureRandom;
  68. private IAccountManager&MockObject $accountManager;
  69. private IEventDispatcher&MockObject $eventDispatcher;
  70. private FederatedShareProvider&MockObject $federatedShareProvider;
  71. private IPublicShareTemplateFactory&MockObject $publicShareTemplateFactory;
  72. protected function setUp(): void {
  73. parent::setUp();
  74. $this->appName = 'files_sharing';
  75. $this->shareManager = $this->createMock(Manager::class);
  76. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  77. $this->session = $this->createMock(ISession::class);
  78. $this->previewManager = $this->createMock(IPreview::class);
  79. $this->config = $this->createMock(IConfig::class);
  80. $this->appConfig = $this->createMock(IAppConfig::class);
  81. $this->userManager = $this->createMock(IUserManager::class);
  82. $this->initialState = $this->createMock(IInitialState::class);
  83. $this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
  84. $this->federatedShareProvider->expects($this->any())
  85. ->method('isOutgoingServer2serverShareEnabled')->willReturn(true);
  86. $this->federatedShareProvider->expects($this->any())
  87. ->method('isIncomingServer2serverShareEnabled')->willReturn(true);
  88. $this->accountManager = $this->createMock(IAccountManager::class);
  89. $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
  90. $this->l10n = $this->createMock(IL10N::class);
  91. $this->secureRandom = $this->createMock(ISecureRandom::class);
  92. $this->defaults = $this->createMock(Defaults::class);
  93. $this->publicShareTemplateFactory = $this->createMock(IPublicShareTemplateFactory::class);
  94. $this->publicShareTemplateFactory
  95. ->expects($this->any())
  96. ->method('getProvider')
  97. ->willReturn(
  98. new DefaultPublicShareTemplateProvider(
  99. $this->userManager,
  100. $this->accountManager,
  101. $this->previewManager,
  102. $this->federatedShareProvider,
  103. $this->urlGenerator,
  104. $this->eventDispatcher,
  105. $this->l10n,
  106. $this->defaults,
  107. $this->config,
  108. $this->createMock(IRequest::class),
  109. $this->initialState,
  110. $this->appConfig,
  111. )
  112. );
  113. $this->shareController = new ShareController(
  114. $this->appName,
  115. $this->createMock(IRequest::class),
  116. $this->config,
  117. $this->urlGenerator,
  118. $this->userManager,
  119. $this->createMock(IManager::class),
  120. $this->shareManager,
  121. $this->session,
  122. $this->previewManager,
  123. $this->createMock(IRootFolder::class),
  124. $this->federatedShareProvider,
  125. $this->accountManager,
  126. $this->eventDispatcher,
  127. $this->l10n,
  128. $this->secureRandom,
  129. $this->defaults,
  130. $this->publicShareTemplateFactory,
  131. );
  132. // Store current user
  133. $this->oldUser = \OC_User::getUser();
  134. // Create a dummy user
  135. $this->user = \OC::$server->getSecureRandom()->generate(12, ISecureRandom::CHAR_LOWER);
  136. \OC::$server->getUserManager()->createUser($this->user, $this->user);
  137. \OC_Util::tearDownFS();
  138. $this->loginAsUser($this->user);
  139. }
  140. protected function tearDown(): void {
  141. \OC_Util::tearDownFS();
  142. \OC_User::setUserId('');
  143. Filesystem::tearDown();
  144. $user = \OC::$server->getUserManager()->get($this->user);
  145. if ($user !== null) {
  146. $user->delete();
  147. }
  148. \OC_User::setIncognitoMode(false);
  149. \OC::$server->getSession()->set('public_link_authenticated', '');
  150. // Set old user
  151. \OC_User::setUserId($this->oldUser);
  152. \OC_Util::setupFS($this->oldUser);
  153. parent::tearDown();
  154. }
  155. public function testShowShareInvalidToken(): void {
  156. $this->shareController->setToken('invalidtoken');
  157. $this->shareManager
  158. ->expects($this->once())
  159. ->method('getShareByToken')
  160. ->with('invalidtoken')
  161. ->will($this->throwException(new ShareNotFound()));
  162. $this->expectException(NotFoundException::class);
  163. // Test without a not existing token
  164. $this->shareController->showShare();
  165. }
  166. public function testShowShareNotAuthenticated(): void {
  167. $this->shareController->setToken('validtoken');
  168. $share = \OC::$server->getShareManager()->newShare();
  169. $share->setPassword('password');
  170. $this->shareManager
  171. ->expects($this->once())
  172. ->method('getShareByToken')
  173. ->with('validtoken')
  174. ->willReturn($share);
  175. $this->expectException(NotFoundException::class);
  176. // Test without a not existing token
  177. $this->shareController->showShare();
  178. }
  179. public function testShowShare(): void {
  180. $note = 'personal note';
  181. $filename = 'file1.txt';
  182. $this->shareController->setToken('token');
  183. $owner = $this->createMock(IUser::class);
  184. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  185. $owner->method('getUID')->willReturn('ownerUID');
  186. $owner->method('isEnabled')->willReturn(true);
  187. $initiator = $this->createMock(IUser::class);
  188. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  189. $initiator->method('getUID')->willReturn('initiatorUID');
  190. $initiator->method('isEnabled')->willReturn(true);
  191. $file = $this->createMock(File::class);
  192. $file->method('getName')->willReturn($filename);
  193. $file->method('getMimetype')->willReturn('text/plain');
  194. $file->method('getSize')->willReturn(33);
  195. $file->method('isReadable')->willReturn(true);
  196. $file->method('isShareable')->willReturn(true);
  197. $file->method('getId')->willReturn(111);
  198. $accountName = $this->createMock(IAccountProperty::class);
  199. $accountName->method('getScope')
  200. ->willReturn(IAccountManager::SCOPE_PUBLISHED);
  201. $account = $this->createMock(IAccount::class);
  202. $account->method('getProperty')
  203. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  204. ->willReturn($accountName);
  205. $this->accountManager->expects($this->once())
  206. ->method('getAccount')
  207. ->with($owner)
  208. ->willReturn($account);
  209. /** @var Manager */
  210. $manager = Server::get(Manager::class);
  211. $share = $manager->newShare();
  212. $share->setId(42)
  213. ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE)
  214. ->setPassword('password')
  215. ->setShareOwner('ownerUID')
  216. ->setSharedBy('initiatorUID')
  217. ->setNode($file)
  218. ->setNote($note)
  219. ->setTarget("/$filename")
  220. ->setToken('token');
  221. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  222. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  223. $this->urlGenerator->expects(self::atLeast(2))
  224. ->method('linkToRouteAbsolute')
  225. ->willReturnMap([
  226. // every file has the show show share url in the opengraph url prop
  227. ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'],
  228. // this share is not an image to the default preview is used
  229. ['files_sharing.PublicPreview.getPreview', ['x' => 256, 'y' => 256, 'file' => $share->getTarget(), 'token' => 'token'], 'previewUrl'],
  230. // for the direct link
  231. ['files_sharing.sharecontroller.downloadShare', ['token' => 'token', 'filename' => $filename ], 'downloadUrl'],
  232. ]);
  233. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  234. $this->config->method('getSystemValue')
  235. ->willReturnMap(
  236. [
  237. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  238. ['enable_previews', true, true],
  239. ['preview_max_x', 1024, 1024],
  240. ['preview_max_y', 1024, 1024],
  241. ]
  242. );
  243. $this->shareManager
  244. ->expects($this->once())
  245. ->method('getShareByToken')
  246. ->with('token')
  247. ->willReturn($share);
  248. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  249. if ($uid === 'ownerUID') {
  250. return $owner;
  251. }
  252. if ($uid === 'initiatorUID') {
  253. return $initiator;
  254. }
  255. return null;
  256. });
  257. $this->eventDispatcher->method('dispatchTyped')->with(
  258. $this->callback(function ($event) use ($share) {
  259. if ($event instanceof BeforeTemplateRenderedEvent) {
  260. return $event->getShare() === $share;
  261. } else {
  262. return true;
  263. }
  264. })
  265. );
  266. $this->l10n->expects($this->any())
  267. ->method('t')
  268. ->willReturnCallback(function ($text, $parameters) {
  269. return vsprintf($text, $parameters);
  270. });
  271. $this->defaults->expects(self::any())
  272. ->method('getProductName')
  273. ->willReturn('Nextcloud');
  274. // Ensure the correct initial state is setup
  275. // Shared node is a file so this is a single file share:
  276. $view = 'public-file-share';
  277. // Set up initial state
  278. $initialState = [];
  279. $this->initialState->expects(self::any())
  280. ->method('provideInitialState')
  281. ->willReturnCallback(function ($key, $value) use (&$initialState): void {
  282. $initialState[$key] = $value;
  283. });
  284. $expectedInitialState = [
  285. 'isPublic' => true,
  286. 'sharingToken' => 'token',
  287. 'sharePermissions' => (Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE),
  288. 'filename' => $filename,
  289. 'view' => $view,
  290. 'fileId' => 111,
  291. ];
  292. $response = $this->shareController->showShare();
  293. $this->assertEquals($expectedInitialState, $initialState);
  294. $csp = new ContentSecurityPolicy();
  295. $csp->addAllowedFrameDomain('\'self\'');
  296. $expectedResponse = new PublicTemplateResponse('files', 'index');
  297. $expectedResponse->setParams(['pageTitle' => $filename]);
  298. $expectedResponse->setContentSecurityPolicy($csp);
  299. $expectedResponse->setHeaderTitle($filename);
  300. $expectedResponse->setHeaderDetails('shared by ownerDisplay');
  301. $expectedResponse->setHeaderActions([
  302. new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', 'downloadUrl', 0, '33'),
  303. new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', 'owner', 'ownerDisplay', $filename),
  304. new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'downloadUrl'),
  305. ]);
  306. $this->assertEquals($expectedResponse, $response);
  307. }
  308. public function testShowFileDropShare(): void {
  309. $filename = 'folder1';
  310. $this->shareController->setToken('token');
  311. $owner = $this->createMock(IUser::class);
  312. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  313. $owner->method('getUID')->willReturn('ownerUID');
  314. $owner->method('isEnabled')->willReturn(true);
  315. $initiator = $this->createMock(IUser::class);
  316. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  317. $initiator->method('getUID')->willReturn('initiatorUID');
  318. $initiator->method('isEnabled')->willReturn(true);
  319. $file = $this->createMock(Folder::class);
  320. $file->method('isReadable')->willReturn(true);
  321. $file->method('isShareable')->willReturn(true);
  322. $file->method('getId')->willReturn(1234);
  323. $file->method('getName')->willReturn($filename);
  324. $accountName = $this->createMock(IAccountProperty::class);
  325. $accountName->method('getScope')
  326. ->willReturn(IAccountManager::SCOPE_PUBLISHED);
  327. $account = $this->createMock(IAccount::class);
  328. $account->method('getProperty')
  329. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  330. ->willReturn($accountName);
  331. $this->accountManager->expects($this->once())
  332. ->method('getAccount')
  333. ->with($owner)
  334. ->willReturn($account);
  335. /** @var Manager */
  336. $manager = Server::get(Manager::class);
  337. $share = $manager->newShare();
  338. $share->setId(42)
  339. ->setPermissions(Constants::PERMISSION_CREATE)
  340. ->setPassword('password')
  341. ->setShareOwner('ownerUID')
  342. ->setSharedBy('initiatorUID')
  343. ->setNode($file)
  344. ->setTarget("/$filename")
  345. ->setToken('token');
  346. $this->appConfig
  347. ->expects($this->once())
  348. ->method('getValueString')
  349. ->with('core', 'shareapi_public_link_disclaimertext', '')
  350. ->willReturn('My disclaimer text');
  351. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  352. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  353. $this->urlGenerator->expects(self::atLeastOnce())
  354. ->method('linkToRouteAbsolute')
  355. ->willReturnMap([
  356. // every file has the show show share url in the opengraph url prop
  357. ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'],
  358. // there is no preview or folders so no other link for opengraph
  359. ]);
  360. $this->config->method('getSystemValue')
  361. ->willReturnMap(
  362. [
  363. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  364. ['enable_previews', true, true],
  365. ['preview_max_x', 1024, 1024],
  366. ['preview_max_y', 1024, 1024],
  367. ]
  368. );
  369. $this->shareManager
  370. ->expects($this->once())
  371. ->method('getShareByToken')
  372. ->with('token')
  373. ->willReturn($share);
  374. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  375. if ($uid === 'ownerUID') {
  376. return $owner;
  377. }
  378. if ($uid === 'initiatorUID') {
  379. return $initiator;
  380. }
  381. return null;
  382. });
  383. $this->eventDispatcher->method('dispatchTyped')->with(
  384. $this->callback(function ($event) use ($share) {
  385. if ($event instanceof BeforeTemplateRenderedEvent) {
  386. return $event->getShare() === $share;
  387. } else {
  388. return true;
  389. }
  390. })
  391. );
  392. $this->l10n->expects($this->any())
  393. ->method('t')
  394. ->willReturnCallback(function ($text, $parameters) {
  395. return vsprintf($text, $parameters);
  396. });
  397. // Set up initial state
  398. $initialState = [];
  399. $this->initialState->expects(self::any())
  400. ->method('provideInitialState')
  401. ->willReturnCallback(function ($key, $value) use (&$initialState): void {
  402. $initialState[$key] = $value;
  403. });
  404. $expectedInitialState = [
  405. 'isPublic' => true,
  406. 'sharingToken' => 'token',
  407. 'sharePermissions' => Constants::PERMISSION_CREATE,
  408. 'filename' => $filename,
  409. 'view' => 'public-file-drop',
  410. 'disclaimer' => 'My disclaimer text',
  411. ];
  412. $response = $this->shareController->showShare();
  413. $this->assertEquals($expectedInitialState, $initialState);
  414. $csp = new ContentSecurityPolicy();
  415. $csp->addAllowedFrameDomain('\'self\'');
  416. $expectedResponse = new PublicTemplateResponse('files', 'index');
  417. $expectedResponse->setParams(['pageTitle' => $filename]);
  418. $expectedResponse->setContentSecurityPolicy($csp);
  419. $expectedResponse->setHeaderTitle($filename);
  420. $expectedResponse->setHeaderDetails('shared by ownerDisplay');
  421. $expectedResponse->setHeaderActions([
  422. new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'shareUrl'),
  423. ]);
  424. $this->assertEquals($expectedResponse, $response);
  425. }
  426. public function testShowShareWithPrivateName(): void {
  427. $note = 'personal note';
  428. $filename = 'file1.txt';
  429. $this->shareController->setToken('token');
  430. $owner = $this->createMock(IUser::class);
  431. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  432. $owner->method('getUID')->willReturn('ownerUID');
  433. $owner->method('isEnabled')->willReturn(true);
  434. $initiator = $this->createMock(IUser::class);
  435. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  436. $initiator->method('getUID')->willReturn('initiatorUID');
  437. $initiator->method('isEnabled')->willReturn(true);
  438. $file = $this->createMock(File::class);
  439. $file->method('getName')->willReturn($filename);
  440. $file->method('getMimetype')->willReturn('text/plain');
  441. $file->method('getSize')->willReturn(33);
  442. $file->method('isReadable')->willReturn(true);
  443. $file->method('isShareable')->willReturn(true);
  444. $file->method('getId')->willReturn(111);
  445. $accountName = $this->createMock(IAccountProperty::class);
  446. $accountName->method('getScope')
  447. ->willReturn(IAccountManager::SCOPE_LOCAL);
  448. $account = $this->createMock(IAccount::class);
  449. $account->method('getProperty')
  450. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  451. ->willReturn($accountName);
  452. $this->accountManager->expects($this->once())
  453. ->method('getAccount')
  454. ->with($owner)
  455. ->willReturn($account);
  456. /** @var IShare */
  457. $share = Server::get(Manager::class)->newShare();
  458. $share->setId(42);
  459. $share->setPassword('password')
  460. ->setShareOwner('ownerUID')
  461. ->setSharedBy('initiatorUID')
  462. ->setNode($file)
  463. ->setNote($note)
  464. ->setToken('token')
  465. ->setPermissions(Constants::PERMISSION_ALL & ~Constants::PERMISSION_SHARE)
  466. ->setTarget("/$filename");
  467. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  468. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  469. $this->urlGenerator->expects(self::atLeast(2))
  470. ->method('linkToRouteAbsolute')
  471. ->willReturnMap([
  472. // every file has the show show share url in the opengraph url prop
  473. ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'],
  474. // this share is not an image to the default preview is used
  475. ['files_sharing.PublicPreview.getPreview', ['x' => 256, 'y' => 256, 'file' => $share->getTarget(), 'token' => 'token'], 'previewUrl'],
  476. // for the direct link
  477. ['files_sharing.sharecontroller.downloadShare', ['token' => 'token', 'filename' => $filename ], 'downloadUrl'],
  478. ]);
  479. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  480. $this->config->method('getSystemValue')
  481. ->willReturnMap(
  482. [
  483. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  484. ['enable_previews', true, true],
  485. ['preview_max_x', 1024, 1024],
  486. ['preview_max_y', 1024, 1024],
  487. ]
  488. );
  489. $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
  490. $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
  491. $this->shareManager
  492. ->expects($this->once())
  493. ->method('getShareByToken')
  494. ->with('token')
  495. ->willReturn($share);
  496. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  497. if ($uid === 'ownerUID') {
  498. return $owner;
  499. }
  500. if ($uid === 'initiatorUID') {
  501. return $initiator;
  502. }
  503. return null;
  504. });
  505. $this->eventDispatcher->method('dispatchTyped')->with(
  506. $this->callback(function ($event) use ($share) {
  507. if ($event instanceof BeforeTemplateRenderedEvent) {
  508. return $event->getShare() === $share;
  509. } else {
  510. return true;
  511. }
  512. })
  513. );
  514. $this->l10n->expects($this->any())
  515. ->method('t')
  516. ->will($this->returnCallback(function ($text, $parameters) {
  517. return vsprintf($text, $parameters);
  518. }));
  519. $this->defaults->expects(self::any())
  520. ->method('getProductName')
  521. ->willReturn('Nextcloud');
  522. $response = $this->shareController->showShare();
  523. $csp = new ContentSecurityPolicy();
  524. $csp->addAllowedFrameDomain('\'self\'');
  525. $expectedResponse = new PublicTemplateResponse('files', 'index');
  526. $expectedResponse->setParams(['pageTitle' => $filename]);
  527. $expectedResponse->setContentSecurityPolicy($csp);
  528. $expectedResponse->setHeaderTitle($filename);
  529. $expectedResponse->setHeaderDetails('');
  530. $expectedResponse->setHeaderActions([
  531. new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', 'downloadUrl', 0, '33'),
  532. new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', 'owner', 'ownerDisplay', $filename),
  533. new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'downloadUrl'),
  534. ]);
  535. $this->assertEquals($expectedResponse, $response);
  536. }
  537. public function testShowShareInvalid(): void {
  538. $this->expectException(NotFoundException::class);
  539. $filename = 'file1.txt';
  540. $this->shareController->setToken('token');
  541. $owner = $this->getMockBuilder(IUser::class)->getMock();
  542. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  543. $owner->method('getUID')->willReturn('ownerUID');
  544. $file = $this->getMockBuilder('OCP\Files\File')->getMock();
  545. $file->method('getName')->willReturn($filename);
  546. $file->method('getMimetype')->willReturn('text/plain');
  547. $file->method('getSize')->willReturn(33);
  548. $file->method('isShareable')->willReturn(false);
  549. $file->method('isReadable')->willReturn(true);
  550. $share = \OC::$server->getShareManager()->newShare();
  551. $share->setId(42);
  552. $share->setPassword('password')
  553. ->setShareOwner('ownerUID')
  554. ->setNode($file)
  555. ->setTarget("/$filename");
  556. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  557. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  558. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  559. $this->config->method('getSystemValue')
  560. ->willReturnMap(
  561. [
  562. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  563. ['enable_previews', true, true],
  564. ]
  565. );
  566. $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
  567. $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
  568. $this->shareManager
  569. ->expects($this->once())
  570. ->method('getShareByToken')
  571. ->with('token')
  572. ->willReturn($share);
  573. $this->userManager->method('get')->with('ownerUID')->willReturn($owner);
  574. $this->shareController->showShare();
  575. }
  576. public function testDownloadShareWithCreateOnlyShare(): void {
  577. $share = $this->getMockBuilder(IShare::class)->getMock();
  578. $share->method('getPassword')->willReturn('password');
  579. $share
  580. ->expects($this->once())
  581. ->method('getPermissions')
  582. ->willReturn(Constants::PERMISSION_CREATE);
  583. $this->shareManager
  584. ->expects($this->once())
  585. ->method('getShareByToken')
  586. ->with('validtoken')
  587. ->willReturn($share);
  588. // Test with a password protected share and no authentication
  589. $response = $this->shareController->downloadShare('validtoken');
  590. $expectedResponse = new DataResponse('Share has no read permission');
  591. $this->assertEquals($expectedResponse, $response);
  592. }
  593. public function testDisabledOwner(): void {
  594. $this->shareController->setToken('token');
  595. $owner = $this->getMockBuilder(IUser::class)->getMock();
  596. $owner->method('isEnabled')->willReturn(false);
  597. $initiator = $this->createMock(IUser::class);
  598. $initiator->method('isEnabled')->willReturn(false);
  599. /* @var MockObject|Folder $folder */
  600. $folder = $this->createMock(Folder::class);
  601. $share = \OC::$server->getShareManager()->newShare();
  602. $share->setId(42);
  603. $share->setPermissions(Constants::PERMISSION_CREATE)
  604. ->setShareOwner('ownerUID')
  605. ->setSharedBy('initiatorUID')
  606. ->setNode($folder)
  607. ->setTarget('/share');
  608. $this->shareManager
  609. ->expects($this->once())
  610. ->method('getShareByToken')
  611. ->with('token')
  612. ->willReturn($share);
  613. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  614. if ($uid === 'ownerUID') {
  615. return $owner;
  616. }
  617. if ($uid === 'initiatorUID') {
  618. return $initiator;
  619. }
  620. return null;
  621. });
  622. $this->expectException(NotFoundException::class);
  623. $this->shareController->showShare();
  624. }
  625. public function testDisabledInitiator(): void {
  626. $this->shareController->setToken('token');
  627. $owner = $this->getMockBuilder(IUser::class)->getMock();
  628. $owner->method('isEnabled')->willReturn(false);
  629. $initiator = $this->createMock(IUser::class);
  630. $initiator->method('isEnabled')->willReturn(true);
  631. /* @var MockObject|Folder $folder */
  632. $folder = $this->createMock(Folder::class);
  633. $share = \OC::$server->getShareManager()->newShare();
  634. $share->setId(42);
  635. $share->setPermissions(Constants::PERMISSION_CREATE)
  636. ->setShareOwner('ownerUID')
  637. ->setSharedBy('initiatorUID')
  638. ->setNode($folder)
  639. ->setTarget('/share');
  640. $this->shareManager
  641. ->expects($this->once())
  642. ->method('getShareByToken')
  643. ->with('token')
  644. ->willReturn($share);
  645. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  646. if ($uid === 'ownerUID') {
  647. return $owner;
  648. }
  649. if ($uid === 'initiatorUID') {
  650. return $initiator;
  651. }
  652. return null;
  653. });
  654. $this->expectException(NotFoundException::class);
  655. $this->shareController->showShare();
  656. }
  657. }