ShareControllerTest.php 25 KB

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