PublicPreviewController.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OCA\Files_Sharing\Controller;
  7. use OCP\AppFramework\Http;
  8. use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
  9. use OCP\AppFramework\Http\Attribute\PublicPage;
  10. use OCP\AppFramework\Http\DataResponse;
  11. use OCP\AppFramework\Http\FileDisplayResponse;
  12. use OCP\AppFramework\PublicShareController;
  13. use OCP\Constants;
  14. use OCP\Files\Folder;
  15. use OCP\Files\NotFoundException;
  16. use OCP\IPreview;
  17. use OCP\IRequest;
  18. use OCP\ISession;
  19. use OCP\Share\Exceptions\ShareNotFound;
  20. use OCP\Share\IManager as ShareManager;
  21. use OCP\Share\IShare;
  22. class PublicPreviewController extends PublicShareController {
  23. /** @var ShareManager */
  24. private $shareManager;
  25. /** @var IPreview */
  26. private $previewManager;
  27. /** @var IShare */
  28. private $share;
  29. public function __construct(string $appName,
  30. IRequest $request,
  31. ShareManager $shareManger,
  32. ISession $session,
  33. IPreview $previewManager) {
  34. parent::__construct($appName, $request, $session);
  35. $this->shareManager = $shareManger;
  36. $this->previewManager = $previewManager;
  37. }
  38. protected function getPasswordHash(): ?string {
  39. return $this->share->getPassword();
  40. }
  41. public function isValidToken(): bool {
  42. try {
  43. $this->share = $this->shareManager->getShareByToken($this->getToken());
  44. return true;
  45. } catch (ShareNotFound $e) {
  46. return false;
  47. }
  48. }
  49. protected function isPasswordProtected(): bool {
  50. return $this->share->getPassword() !== null;
  51. }
  52. /**
  53. * Get a preview for a shared file
  54. *
  55. * @param string $token Token of the share
  56. * @param string $file File in the share
  57. * @param int $x Width of the preview
  58. * @param int $y Height of the preview
  59. * @param bool $a Whether to not crop the preview
  60. * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
  61. *
  62. * 200: Preview returned
  63. * 400: Getting preview is not possible
  64. * 403: Getting preview is not allowed
  65. * 404: Share or preview not found
  66. */
  67. #[PublicPage]
  68. #[NoCSRFRequired]
  69. public function getPreview(
  70. string $token,
  71. string $file = '',
  72. int $x = 32,
  73. int $y = 32,
  74. $a = false
  75. ) {
  76. if ($token === '' || $x === 0 || $y === 0) {
  77. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  78. }
  79. try {
  80. $share = $this->shareManager->getShareByToken($token);
  81. } catch (ShareNotFound $e) {
  82. return new DataResponse([], Http::STATUS_NOT_FOUND);
  83. }
  84. if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
  85. return new DataResponse([], Http::STATUS_FORBIDDEN);
  86. }
  87. $attributes = $share->getAttributes();
  88. if ($attributes !== null && $attributes->getAttribute('permissions', 'download') === false) {
  89. return new DataResponse([], Http::STATUS_FORBIDDEN);
  90. }
  91. try {
  92. $node = $share->getNode();
  93. if ($node instanceof Folder) {
  94. $file = $node->get($file);
  95. } else {
  96. $file = $node;
  97. }
  98. $f = $this->previewManager->getPreview($file, $x, $y, !$a);
  99. $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
  100. $response->cacheFor(3600 * 24);
  101. return $response;
  102. } catch (NotFoundException $e) {
  103. return new DataResponse([], Http::STATUS_NOT_FOUND);
  104. } catch (\InvalidArgumentException $e) {
  105. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  106. }
  107. }
  108. /**
  109. * @NoSameSiteCookieRequired
  110. *
  111. * Get a direct link preview for a shared file
  112. *
  113. * @param string $token Token of the share
  114. * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
  115. *
  116. * 200: Preview returned
  117. * 400: Getting preview is not possible
  118. * 403: Getting preview is not allowed
  119. * 404: Share or preview not found
  120. */
  121. #[PublicPage]
  122. #[NoCSRFRequired]
  123. public function directLink(string $token) {
  124. // No token no image
  125. if ($token === '') {
  126. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  127. }
  128. // No share no image
  129. try {
  130. $share = $this->shareManager->getShareByToken($token);
  131. } catch (ShareNotFound $e) {
  132. return new DataResponse([], Http::STATUS_NOT_FOUND);
  133. }
  134. // No permissions no image
  135. if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
  136. return new DataResponse([], Http::STATUS_FORBIDDEN);
  137. }
  138. // Password protected shares have no direct link!
  139. if ($share->getPassword() !== null) {
  140. return new DataResponse([], Http::STATUS_FORBIDDEN);
  141. }
  142. $attributes = $share->getAttributes();
  143. if ($attributes !== null && $attributes->getAttribute('permissions', 'download') === false) {
  144. return new DataResponse([], Http::STATUS_FORBIDDEN);
  145. }
  146. try {
  147. $node = $share->getNode();
  148. if ($node instanceof Folder) {
  149. // Direct link only works for single files
  150. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  151. }
  152. $f = $this->previewManager->getPreview($node, -1, -1, false);
  153. $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
  154. $response->cacheFor(3600 * 24);
  155. return $response;
  156. } catch (NotFoundException $e) {
  157. return new DataResponse([], Http::STATUS_NOT_FOUND);
  158. } catch (\InvalidArgumentException $e) {
  159. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  160. }
  161. }
  162. }