ShareControllerTest.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Bjoern Schiessle <bjoern@schiessle.org>
  6. * @author Björn Schießle <bjoern@schiessle.org>
  7. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  8. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  9. * @author Georg Ehrke <oc.list@georgehrke.com>
  10. * @author Joas Schilling <coding@schilljs.com>
  11. * @author John Molakvoæ <skjnldsv@protonmail.com>
  12. * @author Julius Härtl <jus@bitgrid.net>
  13. * @author Lukas Reschke <lukas@statuscode.ch>
  14. * @author Michael Weimann <mail@michael-weimann.eu>
  15. * @author Morris Jobke <hey@morrisjobke.de>
  16. * @author Robin Appelman <robin@icewind.nl>
  17. * @author Roeland Jago Douma <roeland@famdouma.nl>
  18. * @author Thomas Müller <thomas.mueller@tmit.eu>
  19. * @author Vincent Petry <vincent@nextcloud.com>
  20. *
  21. * @license AGPL-3.0
  22. *
  23. * This code is free software: you can redistribute it and/or modify
  24. * it under the terms of the GNU Affero General Public License, version 3,
  25. * as published by the Free Software Foundation.
  26. *
  27. * This program is distributed in the hope that it will be useful,
  28. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  30. * GNU Affero General Public License for more details.
  31. *
  32. * You should have received a copy of the GNU Affero General Public License, version 3,
  33. * along with this program. If not, see <http://www.gnu.org/licenses/>
  34. *
  35. */
  36. namespace OCA\Files_Sharing\Tests\Controllers;
  37. use OC\Files\Filesystem;
  38. use OC\Files\Node\Folder;
  39. use OCA\FederatedFileSharing\FederatedShareProvider;
  40. use OCA\Files_Sharing\Controller\ShareController;
  41. use OCP\Accounts\IAccount;
  42. use OCP\Accounts\IAccountManager;
  43. use OCP\Accounts\IAccountProperty;
  44. use OCP\AppFramework\Http\DataResponse;
  45. use OCP\AppFramework\Http\Template\ExternalShareMenuAction;
  46. use OCP\AppFramework\Http\Template\LinkMenuAction;
  47. use OCP\AppFramework\Http\Template\PublicTemplateResponse;
  48. use OCP\AppFramework\Http\Template\SimpleMenuAction;
  49. use OCP\Constants;
  50. use OCP\EventDispatcher\IEventDispatcher;
  51. use OCP\Files\File;
  52. use OCP\Files\NotFoundException;
  53. use OCP\Files\Storage;
  54. use OCP\IConfig;
  55. use OCP\IL10N;
  56. use OCP\IPreview;
  57. use OCP\IRequest;
  58. use OCP\ISession;
  59. use OCP\IURLGenerator;
  60. use OCP\IUser;
  61. use OCP\IUserManager;
  62. use OCP\Security\ISecureRandom;
  63. use OCP\Share\Exceptions\ShareNotFound;
  64. use OCP\Share\IShare;
  65. use PHPUnit\Framework\MockObject\MockObject;
  66. use OCP\Activity\IManager;
  67. use OCP\Files\IRootFolder;
  68. use OCP\Defaults;
  69. use OC\Share20\Manager;
  70. use OCA\Files_Sharing\DefaultPublicShareTemplateProvider;
  71. use OCP\Share\IPublicShareTemplateFactory;
  72. /**
  73. * @group DB
  74. *
  75. * @package OCA\Files_Sharing\Controllers
  76. */
  77. class ShareControllerTest extends \Test\TestCase {
  78. /** @var string */
  79. private $user;
  80. /** @var string */
  81. private $oldUser;
  82. /** @var string */
  83. private $appName = 'files_sharing';
  84. /** @var ShareController */
  85. private $shareController;
  86. /** @var IURLGenerator|MockObject */
  87. private $urlGenerator;
  88. /** @var ISession|MockObject */
  89. private $session;
  90. /** @var \OCP\IPreview|MockObject */
  91. private $previewManager;
  92. /** @var \OCP\IConfig|MockObject */
  93. private $config;
  94. /** @var \OC\Share20\Manager|MockObject */
  95. private $shareManager;
  96. /** @var IUserManager|MockObject */
  97. private $userManager;
  98. /** @var FederatedShareProvider|MockObject */
  99. private $federatedShareProvider;
  100. /** @var IAccountManager|MockObject */
  101. private $accountManager;
  102. /** @var IEventDispatcher|MockObject */
  103. private $eventDispatcher;
  104. /** @var IL10N */
  105. private $l10n;
  106. /** @var ISecureRandom */
  107. private $secureRandom;
  108. /** @var Defaults|MockObject */
  109. private $defaults;
  110. /** @var IPublicShareTemplateFactory|MockObject */
  111. private $publicShareTemplateFactory;
  112. protected function setUp(): void {
  113. parent::setUp();
  114. $this->appName = 'files_sharing';
  115. $this->shareManager = $this->createMock(Manager::class);
  116. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  117. $this->session = $this->createMock(ISession::class);
  118. $this->previewManager = $this->createMock(IPreview::class);
  119. $this->config = $this->createMock(IConfig::class);
  120. $this->userManager = $this->createMock(IUserManager::class);
  121. $this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
  122. $this->federatedShareProvider->expects($this->any())
  123. ->method('isOutgoingServer2serverShareEnabled')->willReturn(true);
  124. $this->federatedShareProvider->expects($this->any())
  125. ->method('isIncomingServer2serverShareEnabled')->willReturn(true);
  126. $this->accountManager = $this->createMock(IAccountManager::class);
  127. $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
  128. $this->l10n = $this->createMock(IL10N::class);
  129. $this->secureRandom = $this->createMock(ISecureRandom::class);
  130. $this->defaults = $this->createMock(Defaults::class);
  131. $this->publicShareTemplateFactory = $this->createMock(IPublicShareTemplateFactory::class);
  132. $this->publicShareTemplateFactory
  133. ->expects($this->any())
  134. ->method('getProvider')
  135. ->willReturn(
  136. new DefaultPublicShareTemplateProvider(
  137. $this->userManager,
  138. $this->accountManager,
  139. $this->previewManager,
  140. $this->federatedShareProvider,
  141. $this->urlGenerator,
  142. $this->eventDispatcher,
  143. $this->l10n,
  144. $this->defaults,
  145. $this->config,
  146. $this->createMock(IRequest::class),
  147. )
  148. );
  149. $this->shareController = new \OCA\Files_Sharing\Controller\ShareController(
  150. $this->appName,
  151. $this->createMock(IRequest::class),
  152. $this->config,
  153. $this->urlGenerator,
  154. $this->userManager,
  155. $this->createMock(IManager::class),
  156. $this->shareManager,
  157. $this->session,
  158. $this->previewManager,
  159. $this->createMock(IRootFolder::class),
  160. $this->federatedShareProvider,
  161. $this->accountManager,
  162. $this->eventDispatcher,
  163. $this->l10n,
  164. $this->secureRandom,
  165. $this->defaults,
  166. $this->publicShareTemplateFactory,
  167. );
  168. // Store current user
  169. $this->oldUser = \OC_User::getUser();
  170. // Create a dummy user
  171. $this->user = \OC::$server->getSecureRandom()->generate(12, ISecureRandom::CHAR_LOWER);
  172. \OC::$server->getUserManager()->createUser($this->user, $this->user);
  173. \OC_Util::tearDownFS();
  174. $this->loginAsUser($this->user);
  175. }
  176. protected function tearDown(): void {
  177. \OC_Util::tearDownFS();
  178. \OC_User::setUserId('');
  179. Filesystem::tearDown();
  180. $user = \OC::$server->getUserManager()->get($this->user);
  181. if ($user !== null) {
  182. $user->delete();
  183. }
  184. \OC_User::setIncognitoMode(false);
  185. \OC::$server->getSession()->set('public_link_authenticated', '');
  186. // Set old user
  187. \OC_User::setUserId($this->oldUser);
  188. \OC_Util::setupFS($this->oldUser);
  189. parent::tearDown();
  190. }
  191. public function testShowShareInvalidToken() {
  192. $this->shareController->setToken('invalidtoken');
  193. $this->shareManager
  194. ->expects($this->once())
  195. ->method('getShareByToken')
  196. ->with('invalidtoken')
  197. ->will($this->throwException(new ShareNotFound()));
  198. $this->expectException(NotFoundException::class);
  199. // Test without a not existing token
  200. $this->shareController->showShare();
  201. }
  202. public function testShowShareNotAuthenticated() {
  203. $this->shareController->setToken('validtoken');
  204. $share = \OC::$server->getShareManager()->newShare();
  205. $share->setPassword('password');
  206. $this->shareManager
  207. ->expects($this->once())
  208. ->method('getShareByToken')
  209. ->with('validtoken')
  210. ->willReturn($share);
  211. $this->expectException(NotFoundException::class);
  212. // Test without a not existing token
  213. $this->shareController->showShare();
  214. }
  215. public function testShowShare() {
  216. $note = 'personal note';
  217. $filename = 'file1.txt';
  218. $this->shareController->setToken('token');
  219. $owner = $this->createMock(IUser::class);
  220. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  221. $owner->method('getUID')->willReturn('ownerUID');
  222. $owner->method('isEnabled')->willReturn(true);
  223. $initiator = $this->createMock(IUser::class);
  224. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  225. $initiator->method('getUID')->willReturn('initiatorUID');
  226. $initiator->method('isEnabled')->willReturn(true);
  227. $file = $this->createMock(File::class);
  228. $file->method('getName')->willReturn($filename);
  229. $file->method('getMimetype')->willReturn('text/plain');
  230. $file->method('getSize')->willReturn(33);
  231. $file->method('isReadable')->willReturn(true);
  232. $file->method('isShareable')->willReturn(true);
  233. $accountName = $this->createMock(IAccountProperty::class);
  234. $accountName->method('getScope')
  235. ->willReturn(IAccountManager::SCOPE_PUBLISHED);
  236. $account = $this->createMock(IAccount::class);
  237. $account->method('getProperty')
  238. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  239. ->willReturn($accountName);
  240. $this->accountManager->expects($this->once())
  241. ->method('getAccount')
  242. ->with($owner)
  243. ->willReturn($account);
  244. $share = \OC::$server->getShareManager()->newShare();
  245. $share->setId(42);
  246. $share->setPassword('password')
  247. ->setShareOwner('ownerUID')
  248. ->setSharedBy('initiatorUID')
  249. ->setNode($file)
  250. ->setNote($note)
  251. ->setTarget("/$filename");
  252. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  253. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  254. $this->urlGenerator->expects($this->exactly(3))
  255. ->method('linkToRouteAbsolute')
  256. ->withConsecutive(
  257. ['files_sharing.sharecontroller.downloadShare', ['token' => 'token', 'filename' => $filename]],
  258. ['files_sharing.sharecontroller.showShare', ['token' => 'token']],
  259. ['files_sharing.PublicPreview.getPreview', ['token' => 'token', 'x' => 200, 'y' => 200, 'file' => '/'.$filename]],
  260. )->willReturnOnConsecutiveCalls(
  261. 'downloadURL',
  262. 'shareUrl',
  263. 'previewImage',
  264. );
  265. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  266. $this->config->method('getSystemValue')
  267. ->willReturnMap(
  268. [
  269. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  270. ['enable_previews', true, true],
  271. ['preview_max_x', 1024, 1024],
  272. ['preview_max_y', 1024, 1024],
  273. ]
  274. );
  275. $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
  276. $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
  277. $this->shareManager
  278. ->expects($this->once())
  279. ->method('getShareByToken')
  280. ->with('token')
  281. ->willReturn($share);
  282. $this->config
  283. ->expects($this->once())
  284. ->method('getAppValue')
  285. ->with('core', 'shareapi_public_link_disclaimertext', null)
  286. ->willReturn('My disclaimer text');
  287. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  288. if ($uid === 'ownerUID') {
  289. return $owner;
  290. }
  291. if ($uid === 'initiatorUID') {
  292. return $initiator;
  293. }
  294. return null;
  295. });
  296. $this->eventDispatcher->expects($this->exactly(2))
  297. ->method('dispatchTyped')
  298. ->with(
  299. $this->callback(function ($event) use ($share) {
  300. return $event->getShare() === $share;
  301. })
  302. );
  303. $this->l10n->expects($this->any())
  304. ->method('t')
  305. ->willReturnCallback(function ($text, $parameters) {
  306. return vsprintf($text, $parameters);
  307. });
  308. $this->defaults->expects(self::any())
  309. ->method('getProductName')
  310. ->willReturn('Nextcloud');
  311. $response = $this->shareController->showShare();
  312. $sharedTmplParams = [
  313. 'owner' => 'ownerUID',
  314. 'filename' => $filename,
  315. 'directory_path' => "/$filename",
  316. 'mimetype' => 'text/plain',
  317. 'dirToken' => 'token',
  318. 'sharingToken' => 'token',
  319. 'server2serversharing' => true,
  320. 'protected' => 'true',
  321. 'dir' => '',
  322. 'downloadURL' => 'downloadURL',
  323. 'fileSize' => '33 B',
  324. 'nonHumanFileSize' => 33,
  325. 'maxSizeAnimateGif' => 10,
  326. 'previewSupported' => true,
  327. 'previewEnabled' => true,
  328. 'previewMaxX' => 1024,
  329. 'previewMaxY' => 1024,
  330. 'hideFileList' => false,
  331. 'shareOwner' => 'ownerDisplay',
  332. 'disclaimer' => 'My disclaimer text',
  333. 'shareUrl' => 'shareUrl',
  334. 'previewImage' => 'previewImage',
  335. 'previewURL' => 'downloadURL',
  336. 'note' => $note,
  337. 'hideDownload' => false,
  338. 'showgridview' => false
  339. ];
  340. $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
  341. $csp->addAllowedFrameDomain('\'self\'');
  342. $expectedResponse = new PublicTemplateResponse($this->appName, 'public', $sharedTmplParams);
  343. $expectedResponse->setContentSecurityPolicy($csp);
  344. $expectedResponse->setHeaderTitle($sharedTmplParams['filename']);
  345. $expectedResponse->setHeaderDetails('shared by ' . $sharedTmplParams['shareOwner']);
  346. $expectedResponse->setHeaderActions([
  347. new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $sharedTmplParams['downloadURL'], 0),
  348. new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $sharedTmplParams['downloadURL'], 10, $sharedTmplParams['fileSize']),
  349. new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $sharedTmplParams['previewURL']),
  350. new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $sharedTmplParams['owner'], $sharedTmplParams['shareOwner'], $sharedTmplParams['filename']),
  351. ]);
  352. $this->assertEquals($expectedResponse, $response);
  353. }
  354. public function testShowShareWithPrivateName() {
  355. $note = 'personal note';
  356. $filename = 'file1.txt';
  357. $this->shareController->setToken('token');
  358. $owner = $this->createMock(IUser::class);
  359. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  360. $owner->method('getUID')->willReturn('ownerUID');
  361. $owner->method('isEnabled')->willReturn(true);
  362. $initiator = $this->createMock(IUser::class);
  363. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  364. $initiator->method('getUID')->willReturn('initiatorUID');
  365. $initiator->method('isEnabled')->willReturn(true);
  366. $file = $this->createMock(File::class);
  367. $file->method('getName')->willReturn($filename);
  368. $file->method('getMimetype')->willReturn('text/plain');
  369. $file->method('getSize')->willReturn(33);
  370. $file->method('isReadable')->willReturn(true);
  371. $file->method('isShareable')->willReturn(true);
  372. $accountName = $this->createMock(IAccountProperty::class);
  373. $accountName->method('getScope')
  374. ->willReturn(IAccountManager::SCOPE_LOCAL);
  375. $account = $this->createMock(IAccount::class);
  376. $account->method('getProperty')
  377. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  378. ->willReturn($accountName);
  379. $this->accountManager->expects($this->once())
  380. ->method('getAccount')
  381. ->with($owner)
  382. ->willReturn($account);
  383. $share = \OC::$server->getShareManager()->newShare();
  384. $share->setId(42);
  385. $share->setPassword('password')
  386. ->setShareOwner('ownerUID')
  387. ->setSharedBy('initiatorUID')
  388. ->setNode($file)
  389. ->setNote($note)
  390. ->setTarget("/$filename");
  391. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  392. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  393. $this->urlGenerator->expects($this->exactly(3))
  394. ->method('linkToRouteAbsolute')
  395. ->withConsecutive(
  396. ['files_sharing.sharecontroller.downloadShare', ['token' => 'token', 'filename' => $filename]],
  397. ['files_sharing.sharecontroller.showShare', ['token' => 'token']],
  398. ['files_sharing.PublicPreview.getPreview', ['token' => 'token', 'x' => 200, 'y' => 200, 'file' => '/'.$filename]],
  399. )->willReturnOnConsecutiveCalls(
  400. 'downloadURL',
  401. 'shareUrl',
  402. 'previewImage',
  403. );
  404. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  405. $this->config->method('getSystemValue')
  406. ->willReturnMap(
  407. [
  408. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  409. ['enable_previews', true, true],
  410. ['preview_max_x', 1024, 1024],
  411. ['preview_max_y', 1024, 1024],
  412. ]
  413. );
  414. $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
  415. $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
  416. $this->shareManager
  417. ->expects($this->once())
  418. ->method('getShareByToken')
  419. ->with('token')
  420. ->willReturn($share);
  421. $this->config
  422. ->expects($this->once())
  423. ->method('getAppValue')
  424. ->with('core', 'shareapi_public_link_disclaimertext', null)
  425. ->willReturn('My disclaimer text');
  426. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  427. if ($uid === 'ownerUID') {
  428. return $owner;
  429. }
  430. if ($uid === 'initiatorUID') {
  431. return $initiator;
  432. }
  433. return null;
  434. });
  435. $this->eventDispatcher->expects($this->exactly(2))
  436. ->method('dispatchTyped')
  437. ->with(
  438. $this->callback(function ($event) use ($share) {
  439. return $event->getShare() === $share;
  440. })
  441. );
  442. $this->l10n->expects($this->any())
  443. ->method('t')
  444. ->will($this->returnCallback(function ($text, $parameters) {
  445. return vsprintf($text, $parameters);
  446. }));
  447. $this->defaults->expects(self::any())
  448. ->method('getProductName')
  449. ->willReturn('Nextcloud');
  450. $response = $this->shareController->showShare();
  451. $sharedTmplParams = [
  452. 'owner' => '',
  453. 'filename' => $filename,
  454. 'directory_path' => "/$filename",
  455. 'mimetype' => 'text/plain',
  456. 'dirToken' => 'token',
  457. 'sharingToken' => 'token',
  458. 'server2serversharing' => true,
  459. 'protected' => 'true',
  460. 'dir' => '',
  461. 'downloadURL' => 'downloadURL',
  462. 'fileSize' => '33 B',
  463. 'nonHumanFileSize' => 33,
  464. 'maxSizeAnimateGif' => 10,
  465. 'previewSupported' => true,
  466. 'previewEnabled' => true,
  467. 'previewMaxX' => 1024,
  468. 'previewMaxY' => 1024,
  469. 'hideFileList' => false,
  470. 'shareOwner' => '',
  471. 'disclaimer' => 'My disclaimer text',
  472. 'shareUrl' => 'shareUrl',
  473. 'previewImage' => 'previewImage',
  474. 'previewURL' => 'downloadURL',
  475. 'note' => $note,
  476. 'hideDownload' => false,
  477. 'showgridview' => false
  478. ];
  479. $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
  480. $csp->addAllowedFrameDomain('\'self\'');
  481. $expectedResponse = new PublicTemplateResponse($this->appName, 'public', $sharedTmplParams);
  482. $expectedResponse->setContentSecurityPolicy($csp);
  483. $expectedResponse->setHeaderTitle($sharedTmplParams['filename']);
  484. $expectedResponse->setHeaderDetails('');
  485. $expectedResponse->setHeaderActions([
  486. new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $sharedTmplParams['downloadURL'], 0),
  487. new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $sharedTmplParams['downloadURL'], 10, $sharedTmplParams['fileSize']),
  488. new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $sharedTmplParams['previewURL']),
  489. new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $sharedTmplParams['owner'], $sharedTmplParams['shareOwner'], $sharedTmplParams['filename']),
  490. ]);
  491. $this->assertEquals($expectedResponse, $response);
  492. }
  493. public function testShowShareHideDownload() {
  494. $note = 'personal note';
  495. $filename = 'file1.txt';
  496. $this->shareController->setToken('token');
  497. $owner = $this->getMockBuilder(IUser::class)->getMock();
  498. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  499. $owner->method('getUID')->willReturn('ownerUID');
  500. $owner->method('isEnabled')->willReturn(true);
  501. $initiator = $this->createMock(IUser::class);
  502. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  503. $initiator->method('getUID')->willReturn('initiatorUID');
  504. $initiator->method('isEnabled')->willReturn(true);
  505. $file = $this->getMockBuilder('OCP\Files\File')->getMock();
  506. $file->method('getName')->willReturn($filename);
  507. $file->method('getMimetype')->willReturn('text/plain');
  508. $file->method('getSize')->willReturn(33);
  509. $file->method('isReadable')->willReturn(true);
  510. $file->method('isShareable')->willReturn(true);
  511. $accountName = $this->createMock(IAccountProperty::class);
  512. $accountName->method('getScope')
  513. ->willReturn(IAccountManager::SCOPE_PUBLISHED);
  514. $account = $this->createMock(IAccount::class);
  515. $account->method('getProperty')
  516. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  517. ->willReturn($accountName);
  518. $this->accountManager->expects($this->once())
  519. ->method('getAccount')
  520. ->with($owner)
  521. ->willReturn($account);
  522. $share = \OC::$server->getShareManager()->newShare();
  523. $share->setId(42);
  524. $share->setPassword('password')
  525. ->setShareOwner('ownerUID')
  526. ->setSharedBy('initiatorUID')
  527. ->setNode($file)
  528. ->setNote($note)
  529. ->setTarget("/$filename")
  530. ->setHideDownload(true);
  531. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  532. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  533. // Even if downloads are disabled the "downloadURL" parameter is
  534. // provided to the template, as it is needed to preview audio and GIF
  535. // files.
  536. $this->urlGenerator->expects($this->exactly(3))
  537. ->method('linkToRouteAbsolute')
  538. ->withConsecutive(
  539. ['files_sharing.sharecontroller.downloadShare', ['token' => 'token', 'filename' => $filename]],
  540. ['files_sharing.sharecontroller.showShare', ['token' => 'token']],
  541. ['files_sharing.PublicPreview.getPreview', ['token' => 'token', 'x' => 200, 'y' => 200, 'file' => '/'.$filename]],
  542. )->willReturnOnConsecutiveCalls(
  543. 'downloadURL',
  544. 'shareUrl',
  545. 'previewImage',
  546. );
  547. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  548. $this->config->method('getSystemValue')
  549. ->willReturnMap(
  550. [
  551. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  552. ['enable_previews', true, true],
  553. ['preview_max_x', 1024, 1024],
  554. ['preview_max_y', 1024, 1024],
  555. ]
  556. );
  557. $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
  558. $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
  559. $this->shareManager
  560. ->expects($this->once())
  561. ->method('getShareByToken')
  562. ->with('token')
  563. ->willReturn($share);
  564. $this->config
  565. ->expects($this->once())
  566. ->method('getAppValue')
  567. ->with('core', 'shareapi_public_link_disclaimertext', null)
  568. ->willReturn('My disclaimer text');
  569. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  570. if ($uid === 'ownerUID') {
  571. return $owner;
  572. }
  573. if ($uid === 'initiatorUID') {
  574. return $initiator;
  575. }
  576. return null;
  577. });
  578. $this->eventDispatcher->expects($this->exactly(2))
  579. ->method('dispatchTyped')
  580. ->with(
  581. $this->callback(function ($event) use ($share) {
  582. return $event->getShare() === $share;
  583. })
  584. );
  585. $this->l10n->expects($this->any())
  586. ->method('t')
  587. ->willReturnCallback(function ($text, $parameters) {
  588. return vsprintf($text, $parameters);
  589. });
  590. $response = $this->shareController->showShare();
  591. $sharedTmplParams = [
  592. 'owner' => 'ownerUID',
  593. 'filename' => $filename,
  594. 'directory_path' => "/$filename",
  595. 'mimetype' => 'text/plain',
  596. 'dirToken' => 'token',
  597. 'sharingToken' => 'token',
  598. 'server2serversharing' => true,
  599. 'protected' => 'true',
  600. 'dir' => '',
  601. 'downloadURL' => 'downloadURL',
  602. 'fileSize' => '33 B',
  603. 'nonHumanFileSize' => 33,
  604. 'maxSizeAnimateGif' => 10,
  605. 'previewSupported' => true,
  606. 'previewEnabled' => true,
  607. 'previewMaxX' => 1024,
  608. 'previewMaxY' => 1024,
  609. 'hideFileList' => false,
  610. 'shareOwner' => 'ownerDisplay',
  611. 'disclaimer' => 'My disclaimer text',
  612. 'shareUrl' => 'shareUrl',
  613. 'previewImage' => 'previewImage',
  614. 'previewURL' => 'downloadURL',
  615. 'note' => $note,
  616. 'hideDownload' => true,
  617. 'showgridview' => false
  618. ];
  619. $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
  620. $csp->addAllowedFrameDomain('\'self\'');
  621. $expectedResponse = new PublicTemplateResponse($this->appName, 'public', $sharedTmplParams);
  622. $expectedResponse->setContentSecurityPolicy($csp);
  623. $expectedResponse->setHeaderTitle($sharedTmplParams['filename']);
  624. $expectedResponse->setHeaderDetails('shared by ' . $sharedTmplParams['shareOwner']);
  625. $expectedResponse->setHeaderActions([]);
  626. $this->assertEquals($expectedResponse, $response);
  627. }
  628. /**
  629. * Checks file drop shares:
  630. * - there must not be any header action
  631. * - the template param "hideFileList" should be true
  632. *
  633. * @test
  634. * @return void
  635. */
  636. public function testShareFileDrop() {
  637. $this->shareController->setToken('token');
  638. $owner = $this->getMockBuilder(IUser::class)->getMock();
  639. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  640. $owner->method('getUID')->willReturn('ownerUID');
  641. $owner->method('isEnabled')->willReturn(true);
  642. $initiator = $this->createMock(IUser::class);
  643. $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
  644. $initiator->method('getUID')->willReturn('initiatorUID');
  645. $initiator->method('isEnabled')->willReturn(true);
  646. /* @var MockObject|Storage $storage */
  647. $storage = $this->getMockBuilder(Storage::class)
  648. ->disableOriginalConstructor()
  649. ->getMock();
  650. /* @var MockObject|Folder $folder */
  651. $folder = $this->getMockBuilder(Folder::class)
  652. ->disableOriginalConstructor()
  653. ->getMock();
  654. $folder->method('getName')->willReturn('/fileDrop');
  655. $folder->method('isReadable')->willReturn(true);
  656. $folder->method('isShareable')->willReturn(true);
  657. $folder->method('getStorage')->willReturn($storage);
  658. $folder->method('get')->with('')->willReturn($folder);
  659. $folder->method('getSize')->willReturn(1337);
  660. $accountName = $this->createMock(IAccountProperty::class);
  661. $accountName->method('getScope')
  662. ->willReturn(IAccountManager::SCOPE_PUBLISHED);
  663. $account = $this->createMock(IAccount::class);
  664. $account->method('getProperty')
  665. ->with(IAccountManager::PROPERTY_DISPLAYNAME)
  666. ->willReturn($accountName);
  667. $this->accountManager->expects($this->once())
  668. ->method('getAccount')
  669. ->with($owner)
  670. ->willReturn($account);
  671. $share = \OC::$server->getShareManager()->newShare();
  672. $share->setId(42);
  673. $share->setPermissions(Constants::PERMISSION_CREATE)
  674. ->setShareOwner('ownerUID')
  675. ->setSharedBy('initiatorUID')
  676. ->setNode($folder)
  677. ->setTarget('/fileDrop');
  678. $this->shareManager
  679. ->expects($this->once())
  680. ->method('getShareByToken')
  681. ->with('token')
  682. ->willReturn($share);
  683. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  684. if ($uid === 'ownerUID') {
  685. return $owner;
  686. }
  687. if ($uid === 'initiatorUID') {
  688. return $initiator;
  689. }
  690. return null;
  691. });
  692. $this->l10n->expects($this->any())
  693. ->method('t')
  694. ->willReturnCallback(function ($text, $parameters) {
  695. return vsprintf($text, $parameters);
  696. });
  697. $response = $this->shareController->showShare();
  698. // skip the "folder" param for tests
  699. $responseParams = $response->getParams();
  700. unset($responseParams['folder']);
  701. $response->setParams($responseParams);
  702. $sharedTmplParams = [
  703. 'owner' => 'ownerUID',
  704. 'filename' => '/fileDrop',
  705. 'directory_path' => '/fileDrop',
  706. 'mimetype' => null,
  707. 'dirToken' => 'token',
  708. 'sharingToken' => 'token',
  709. 'server2serversharing' => true,
  710. 'protected' => 'false',
  711. 'dir' => null,
  712. 'downloadURL' => '',
  713. 'fileSize' => '1 KB',
  714. 'nonHumanFileSize' => 1337,
  715. 'maxSizeAnimateGif' => null,
  716. 'previewSupported' => null,
  717. 'previewEnabled' => null,
  718. 'previewMaxX' => null,
  719. 'previewMaxY' => null,
  720. 'hideFileList' => true,
  721. 'shareOwner' => 'ownerDisplay',
  722. 'disclaimer' => null,
  723. 'shareUrl' => '',
  724. 'previewImage' => '',
  725. 'previewURL' => '',
  726. 'note' => '',
  727. 'hideDownload' => false,
  728. 'showgridview' => false
  729. ];
  730. $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
  731. $csp->addAllowedFrameDomain('\'self\'');
  732. $expectedResponse = new PublicTemplateResponse($this->appName, 'public', $sharedTmplParams);
  733. $expectedResponse->setContentSecurityPolicy($csp);
  734. $expectedResponse->setHeaderTitle($sharedTmplParams['filename']);
  735. $expectedResponse->setHeaderDetails('shared by ' . $sharedTmplParams['shareOwner']);
  736. self::assertEquals($expectedResponse, $response);
  737. }
  738. public function testShowShareInvalid() {
  739. $this->expectException(\OCP\Files\NotFoundException::class);
  740. $filename = 'file1.txt';
  741. $this->shareController->setToken('token');
  742. $owner = $this->getMockBuilder(IUser::class)->getMock();
  743. $owner->method('getDisplayName')->willReturn('ownerDisplay');
  744. $owner->method('getUID')->willReturn('ownerUID');
  745. $file = $this->getMockBuilder('OCP\Files\File')->getMock();
  746. $file->method('getName')->willReturn($filename);
  747. $file->method('getMimetype')->willReturn('text/plain');
  748. $file->method('getSize')->willReturn(33);
  749. $file->method('isShareable')->willReturn(false);
  750. $file->method('isReadable')->willReturn(true);
  751. $share = \OC::$server->getShareManager()->newShare();
  752. $share->setId(42);
  753. $share->setPassword('password')
  754. ->setShareOwner('ownerUID')
  755. ->setNode($file)
  756. ->setTarget("/$filename");
  757. $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
  758. $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
  759. $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
  760. $this->config->method('getSystemValue')
  761. ->willReturnMap(
  762. [
  763. ['max_filesize_animated_gifs_public_sharing', 10, 10],
  764. ['enable_previews', true, true],
  765. ]
  766. );
  767. $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
  768. $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
  769. $this->shareManager
  770. ->expects($this->once())
  771. ->method('getShareByToken')
  772. ->with('token')
  773. ->willReturn($share);
  774. $this->userManager->method('get')->with('ownerUID')->willReturn($owner);
  775. $this->shareController->showShare();
  776. }
  777. public function testDownloadShareWithCreateOnlyShare() {
  778. $share = $this->getMockBuilder(IShare::class)->getMock();
  779. $share->method('getPassword')->willReturn('password');
  780. $share
  781. ->expects($this->once())
  782. ->method('getPermissions')
  783. ->willReturn(\OCP\Constants::PERMISSION_CREATE);
  784. $this->shareManager
  785. ->expects($this->once())
  786. ->method('getShareByToken')
  787. ->with('validtoken')
  788. ->willReturn($share);
  789. // Test with a password protected share and no authentication
  790. $response = $this->shareController->downloadShare('validtoken');
  791. $expectedResponse = new DataResponse('Share has no read permission');
  792. $this->assertEquals($expectedResponse, $response);
  793. }
  794. public function testDisabledOwner() {
  795. $this->shareController->setToken('token');
  796. $owner = $this->getMockBuilder(IUser::class)->getMock();
  797. $owner->method('isEnabled')->willReturn(false);
  798. $initiator = $this->createMock(IUser::class);
  799. $initiator->method('isEnabled')->willReturn(false);
  800. /* @var MockObject|Folder $folder */
  801. $folder = $this->createMock(Folder::class);
  802. $share = \OC::$server->getShareManager()->newShare();
  803. $share->setId(42);
  804. $share->setPermissions(Constants::PERMISSION_CREATE)
  805. ->setShareOwner('ownerUID')
  806. ->setSharedBy('initiatorUID')
  807. ->setNode($folder)
  808. ->setTarget('/share');
  809. $this->shareManager
  810. ->expects($this->once())
  811. ->method('getShareByToken')
  812. ->with('token')
  813. ->willReturn($share);
  814. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  815. if ($uid === 'ownerUID') {
  816. return $owner;
  817. }
  818. if ($uid === 'initiatorUID') {
  819. return $initiator;
  820. }
  821. return null;
  822. });
  823. $this->expectException(NotFoundException::class);
  824. $this->shareController->showShare();
  825. }
  826. public function testDisabledInitiator() {
  827. $this->shareController->setToken('token');
  828. $owner = $this->getMockBuilder(IUser::class)->getMock();
  829. $owner->method('isEnabled')->willReturn(false);
  830. $initiator = $this->createMock(IUser::class);
  831. $initiator->method('isEnabled')->willReturn(true);
  832. /* @var MockObject|Folder $folder */
  833. $folder = $this->createMock(Folder::class);
  834. $share = \OC::$server->getShareManager()->newShare();
  835. $share->setId(42);
  836. $share->setPermissions(Constants::PERMISSION_CREATE)
  837. ->setShareOwner('ownerUID')
  838. ->setSharedBy('initiatorUID')
  839. ->setNode($folder)
  840. ->setTarget('/share');
  841. $this->shareManager
  842. ->expects($this->once())
  843. ->method('getShareByToken')
  844. ->with('token')
  845. ->willReturn($share);
  846. $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) {
  847. if ($uid === 'ownerUID') {
  848. return $owner;
  849. }
  850. if ($uid === 'initiatorUID') {
  851. return $initiator;
  852. }
  853. return null;
  854. });
  855. $this->expectException(NotFoundException::class);
  856. $this->shareController->showShare();
  857. }
  858. }