Skip to content

Commit 8da8a80

Browse files
committed
fix(files_sharing): make legacy downloadShare endpoint compatible with legacy behavior
This needs to be able to directly download files if specified to only download a single file and not a folder. Also it was possible to either pass a files array json encoded or a single file not encoded at all. Signed-off-by: Ferdinand Thiessen <[email protected]>
1 parent 75edec9 commit 8da8a80

File tree

2 files changed

+52
-21
lines changed

2 files changed

+52
-21
lines changed

apps/files_sharing/lib/Controller/ShareController.php

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use OCA\Files_Sharing\Event\ShareLinkAccessedEvent;
1515
use OCP\Accounts\IAccountManager;
1616
use OCP\AppFramework\AuthPublicShareController;
17+
use OCP\AppFramework\Http;
1718
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
1819
use OCP\AppFramework\Http\Attribute\OpenAPI;
1920
use OCP\AppFramework\Http\Attribute\PublicPage;
@@ -29,6 +30,7 @@
2930
use OCP\Files\Folder;
3031
use OCP\Files\IRootFolder;
3132
use OCP\Files\NotFoundException;
33+
use OCP\Files\NotPermittedException;
3234
use OCP\HintException;
3335
use OCP\IConfig;
3436
use OCP\IL10N;
@@ -360,49 +362,75 @@ public function downloadShare($token, $files = null, $path = '') {
360362
$share = $this->shareManager->getShareByToken($token);
361363

362364
if (!($share->getPermissions() & Constants::PERMISSION_READ)) {
363-
return new DataResponse('Share has no read permission');
365+
return new DataResponse('Share has no read permission', Http::STATUS_FORBIDDEN);
364366
}
365367

366368
$attributes = $share->getAttributes();
367369
if ($attributes?->getAttribute('permissions', 'download') === false) {
368-
return new DataResponse('Share has no download permission');
370+
return new DataResponse('Share has no download permission', Http::STATUS_FORBIDDEN);
369371
}
370372

371373
if (!$this->validateShare($share)) {
372374
throw new NotFoundException();
373375
}
374376

377+
if ($share->getHideDownload()) {
378+
// download API does not work if hidden - use the DAV endpoint for previews
379+
throw new NotFoundException();
380+
}
381+
375382
$node = $share->getNode();
376-
if ($node instanceof Folder) {
377-
// Directory share
383+
if ($path !== '') {
384+
if (!$node instanceof Folder) {
385+
return new NotFoundResponse();
386+
}
378387

379-
// Try to get the path
380-
if ($path !== '') {
388+
try {
389+
$node = $node->get($path);
390+
} catch (NotFoundException|NotPermittedException) {
391+
$this->emitAccessShareHook($share, 404, 'Share not found');
392+
$this->emitShareAccessEvent($share, self::SHARE_DOWNLOAD, 404, 'Share not found');
393+
return new NotFoundResponse();
394+
}
395+
}
396+
397+
if ($files !== null) {
398+
if (!$node instanceof Folder) {
399+
return new NotFoundResponse();
400+
}
401+
402+
$filesParam = json_decode($files, true);
403+
if (!is_array($filesParam)) {
381404
try {
382-
$node = $node->get($path);
383-
} catch (NotFoundException $e) {
405+
// legacy wise this allows also passing the filename
406+
$node = $node->get($files);
407+
$files = null;
408+
} catch (NotFoundException|NotPermittedException) {
384409
$this->emitAccessShareHook($share, 404, 'Share not found');
385410
$this->emitShareAccessEvent($share, self::SHARE_DOWNLOAD, 404, 'Share not found');
386411
return new NotFoundResponse();
387412
}
388413
}
389-
390-
if ($node instanceof Folder) {
391-
if ($files === null || $files === '') {
392-
if ($share->getHideDownload()) {
393-
throw new NotFoundException('Downloading a folder');
394-
}
395-
}
396-
}
397414
}
398415

399416
$this->emitAccessShareHook($share);
400417
$this->emitShareAccessEvent($share, self::SHARE_DOWNLOAD);
401418

402-
$davUrl = '/public.php/dav/files/' . $token . '/?accept=zip';
419+
$davPath = '';
420+
if ($node !== $share->getNode()) {
421+
$davPath = substr($node->getPath(), strlen($share->getNode()->getPath()));
422+
}
423+
424+
$params = [];
403425
if ($files !== null) {
404-
$davUrl .= '&files=' . $files;
426+
$params['files'] = $files;
405427
}
428+
if ($node instanceof Folder) {
429+
$params['accept'] = 'zip';
430+
}
431+
432+
$davUrl = '/public.php/dav/files/' . $token . $davPath;
433+
$davUrl .= '?' . http_build_query($params);
406434
return new RedirectResponse($this->urlGenerator->getAbsoluteURL($davUrl));
407435
}
408436
}

apps/files_sharing/tests/Controller/ShareControllerTest.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use OCP\Accounts\IAccountManager;
1919
use OCP\Accounts\IAccountProperty;
2020
use OCP\Activity\IManager;
21+
use OCP\AppFramework\Http;
2122
use OCP\AppFramework\Http\ContentSecurityPolicy;
2223
use OCP\AppFramework\Http\DataResponse;
2324
use OCP\AppFramework\Http\Template\ExternalShareMenuAction;
@@ -691,7 +692,9 @@ public function testShowShareInvalid(): void {
691692
->with('token')
692693
->willReturn($share);
693694

694-
$this->userManager->method('get')->with('ownerUID')->willReturn($owner);
695+
$this->userManager->method('get')
696+
->with('ownerUID')
697+
->willReturn($owner);
695698

696699
$this->shareController->showShare();
697700
}
@@ -712,7 +715,7 @@ public function testDownloadShareWithCreateOnlyShare(): void {
712715

713716
// Test with a password protected share and no authentication
714717
$response = $this->shareController->downloadShare('validtoken');
715-
$expectedResponse = new DataResponse('Share has no read permission');
718+
$expectedResponse = new DataResponse('Share has no read permission', Http::STATUS_FORBIDDEN);
716719
$this->assertEquals($expectedResponse, $response);
717720
}
718721

@@ -740,7 +743,7 @@ public function testDownloadShareWithoutDownloadPermission(): void {
740743

741744
// Test with a password protected share and no authentication
742745
$response = $this->shareController->downloadShare('validtoken');
743-
$expectedResponse = new DataResponse('Share has no download permission');
746+
$expectedResponse = new DataResponse('Share has no download permission', Http::STATUS_FORBIDDEN);
744747
$this->assertEquals($expectedResponse, $response);
745748
}
746749

0 commit comments

Comments
 (0)