123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- <?php
- /**
- * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
- namespace OCA\Files_Sharing\Controller;
- use OCP\AppFramework\Http;
- use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
- use OCP\AppFramework\Http\Attribute\PublicPage;
- use OCP\AppFramework\Http\DataResponse;
- use OCP\AppFramework\Http\FileDisplayResponse;
- use OCP\AppFramework\PublicShareController;
- use OCP\Constants;
- use OCP\Files\Folder;
- use OCP\Files\NotFoundException;
- use OCP\IPreview;
- use OCP\IRequest;
- use OCP\ISession;
- use OCP\Share\Exceptions\ShareNotFound;
- use OCP\Share\IManager as ShareManager;
- use OCP\Share\IShare;
- class PublicPreviewController extends PublicShareController {
- /** @var IShare */
- private $share;
- public function __construct(
- string $appName,
- IRequest $request,
- private ShareManager $shareManager,
- ISession $session,
- private IPreview $previewManager,
- ) {
- parent::__construct($appName, $request, $session);
- }
- protected function getPasswordHash(): ?string {
- return $this->share->getPassword();
- }
- public function isValidToken(): bool {
- try {
- $this->share = $this->shareManager->getShareByToken($this->getToken());
- return true;
- } catch (ShareNotFound $e) {
- return false;
- }
- }
- protected function isPasswordProtected(): bool {
- return $this->share->getPassword() !== null;
- }
- /**
- * Get a preview for a shared file
- *
- * @param string $token Token of the share
- * @param string $file File in the share
- * @param int $x Width of the preview
- * @param int $y Height of the preview
- * @param bool $a Whether to not crop the preview
- * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, list<empty>, array{}>
- *
- * 200: Preview returned
- * 400: Getting preview is not possible
- * 403: Getting preview is not allowed
- * 404: Share or preview not found
- */
- #[PublicPage]
- #[NoCSRFRequired]
- public function getPreview(
- string $token,
- string $file = '',
- int $x = 32,
- int $y = 32,
- $a = false,
- ) {
- $cacheForSeconds = 60 * 60 * 24; // 1 day
- if ($token === '' || $x === 0 || $y === 0) {
- return new DataResponse([], Http::STATUS_BAD_REQUEST);
- }
- try {
- $share = $this->shareManager->getShareByToken($token);
- } catch (ShareNotFound $e) {
- return new DataResponse([], Http::STATUS_NOT_FOUND);
- }
- if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
- return new DataResponse([], Http::STATUS_FORBIDDEN);
- }
- $attributes = $share->getAttributes();
- // Only explicitly set to false will forbid the download!
- $downloadForbidden = $attributes?->getAttribute('permissions', 'download') === false;
- // Is this header is set it means our UI is doing a preview for no-download shares
- // we check a header so we at least prevent people from using the link directly (obfuscation)
- $isPublicPreview = $this->request->getHeader('X-NC-Preview') === 'true';
- if ($isPublicPreview && $downloadForbidden) {
- // Only cache for 15 minutes on public preview requests to quickly remove from cache
- $cacheForSeconds = 15 * 60;
- } elseif ($downloadForbidden) {
- // This is not a public share preview so we only allow a preview if download permissions are granted
- return new DataResponse([], Http::STATUS_FORBIDDEN);
- }
- try {
- $node = $share->getNode();
- if ($node instanceof Folder) {
- $file = $node->get($file);
- } else {
- $file = $node;
- }
- $f = $this->previewManager->getPreview($file, $x, $y, !$a);
- $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
- $response->cacheFor($cacheForSeconds);
- return $response;
- } catch (NotFoundException $e) {
- return new DataResponse([], Http::STATUS_NOT_FOUND);
- } catch (\InvalidArgumentException $e) {
- return new DataResponse([], Http::STATUS_BAD_REQUEST);
- }
- }
- /**
- * @NoSameSiteCookieRequired
- *
- * Get a direct link preview for a shared file
- *
- * @param string $token Token of the share
- * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, list<empty>, array{}>
- *
- * 200: Preview returned
- * 400: Getting preview is not possible
- * 403: Getting preview is not allowed
- * 404: Share or preview not found
- */
- #[PublicPage]
- #[NoCSRFRequired]
- public function directLink(string $token) {
- // No token no image
- if ($token === '') {
- return new DataResponse([], Http::STATUS_BAD_REQUEST);
- }
- // No share no image
- try {
- $share = $this->shareManager->getShareByToken($token);
- } catch (ShareNotFound $e) {
- return new DataResponse([], Http::STATUS_NOT_FOUND);
- }
- // No permissions no image
- if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
- return new DataResponse([], Http::STATUS_FORBIDDEN);
- }
- // Password protected shares have no direct link!
- if ($share->getPassword() !== null) {
- return new DataResponse([], Http::STATUS_FORBIDDEN);
- }
- $attributes = $share->getAttributes();
- if ($attributes !== null && $attributes->getAttribute('permissions', 'download') === false) {
- return new DataResponse([], Http::STATUS_FORBIDDEN);
- }
- try {
- $node = $share->getNode();
- if ($node instanceof Folder) {
- // Direct link only works for single files
- return new DataResponse([], Http::STATUS_BAD_REQUEST);
- }
- $f = $this->previewManager->getPreview($node, -1, -1, false);
- $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
- $response->cacheFor(3600 * 24);
- return $response;
- } catch (NotFoundException $e) {
- return new DataResponse([], Http::STATUS_NOT_FOUND);
- } catch (\InvalidArgumentException $e) {
- return new DataResponse([], Http::STATUS_BAD_REQUEST);
- }
- }
- }
|