Skip to content

Commit f85c1e0

Browse files
committed
fix(api): Respond to missing file with 404
Use exceptions to destinguish between not found and forbidden. We try to not expose wether a file exists or not. But if the file exists but download permissions have not been granted we want to be explicit about that and return a 403 response code. Signed-off-by: Max <max@nextcloud.com>
1 parent 83c97b6 commit f85c1e0

4 files changed

Lines changed: 36 additions & 10 deletions

File tree

cypress/e2e/api/SessionApi.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ describe('The session Api', function() {
5454
})
5555

5656
it('handles missing file id', function() {
57-
cy.failToCreateTextSession().its('status').should('equal', 412)
57+
cy.failToCreateTextSession().its('status').should('equal', 404)
5858
})
5959
})
6060

lib/Context/FileContext.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public function toString(): string {
5757
return $this->getType() . ' (' . $this->getId() . ')';
5858
}
5959

60+
/**
61+
* @throws NotFoundException
62+
* @throws NotPermittedException
63+
*/
6064
#[Override]
6165
public function getFile(): File {
6266
if ($this->file !== null) {
@@ -73,12 +77,23 @@ public function getFile(): File {
7377
return $this->file;
7478
}
7579

80+
/**
81+
* @throws NotFoundException
82+
* @throws NotPermittedException
83+
*/
7684
#[Override]
77-
public function buildDocument(): Document|string {
78-
$file = $this->getFile();
85+
public function buildDocument(): Document {
86+
try {
87+
$file = $this->getFile();
88+
} catch (NotFoundException|NotPermittedException $e) {
89+
$this->logger->warning('No permission to access this file', ['exception' => $e]);
90+
throw new NotFoundException($this->l10n->t('File not found'), $e->getCode(), $e);
91+
}
7992
// Block using text for disabled download internal shares
8093
if ($this->fileService->isDownloadDisabled($file)) {
81-
return $this->l10n->t('This file cannot be displayed as download is disabled by the share');
94+
throw new NotPermittedException(
95+
$this->l10n->t('This file cannot be displayed as download is disabled by the share')
96+
);
8297
}
8398
$document = new Document();
8499
$document->setContextType('file');

lib/Context/IContext.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,25 @@
1111
use OCA\Text\Db\Session;
1212
use OCP\Files\File;
1313
use OCP\Files\Lock\ILock;
14+
use OCP\Files\NotFoundException;
15+
use OCP\Files\NotPermittedException;
1416

1517
interface IContext {
1618
public function getId(): int;
1719
public function getType(): string;
1820
public function toString(): string;
19-
public function buildDocument(): Document|string;
21+
/**
22+
* @throws NotFoundException
23+
* @throws NotPermittedException
24+
*/
25+
public function buildDocument(): Document;
2026
public function prepareSession(DocumentData $documentData): SessionInfo;
2127
public function isReadOnly(): bool;
2228
public function updateDocument(Document $document): ?Document;
29+
/**
30+
* @throws NotFoundException
31+
* @throws NotPermittedException
32+
*/
2333
public function getFile(): ?File;
2434
public function loadContent(): ?string;
2535
public function saveWithLock(string $content, callable $doWhileLocked): void;

lib/Service/ApiService.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use OCP\AppFramework\Db\DoesNotExistException;
2222
use OCP\AppFramework\Http;
2323
use OCP\AppFramework\Http\DataResponse;
24-
use OCP\Files\File;
2524
use OCP\Files\InvalidPathException;
2625
use OCP\Files\NotFoundException;
2726
use OCP\Files\NotPermittedException;
@@ -37,16 +36,18 @@ public function __construct(
3736
private readonly SessionService $sessionService,
3837
private readonly DocumentService $documentService,
3938
private readonly LoggerInterface $logger,
40-
private readonly LockService $lockService,
4139
private readonly IL10N $l10n,
4240
private readonly ?IQueue $queue,
4341
) {
4442
}
4543

4644
public function create(IContext $context, ?string $baseVersionEtag, ?string $guestName = null): DataResponse {
47-
$document = $context->buildDocument();
48-
if (!$document instanceof Document) {
49-
return new DataResponse(['error' => $document], Http::STATUS_FORBIDDEN);
45+
try {
46+
$document = $context->buildDocument();
47+
} catch (NotFoundException $e) {
48+
return new DataResponse(['error' => $e->getMessage()], Http::STATUS_NOT_FOUND);
49+
} catch (NotPermittedException $e) {
50+
return new DataResponse(['error' => $e->getMessage()], Http::STATUS_FORBIDDEN);
5051
}
5152

5253
try {

0 commit comments

Comments
 (0)