You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

803 lines
26 KiB

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