ShareControllerTest.php 32 KB

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