diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index 1ca850198cf8d..752bc379c058a 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -191,7 +191,7 @@ public function createServer($baseUri, // Allow view-only plugin for webdav requests $server->addPlugin(new ViewOnlyPlugin( - $this->psrLogger + $userFolder )); if ($this->userSession->isLoggedIn()) { diff --git a/apps/dav/lib/DAV/ViewOnlyPlugin.php b/apps/dav/lib/DAV/ViewOnlyPlugin.php index 51e3622142db3..200d383cc5872 100644 --- a/apps/dav/lib/DAV/ViewOnlyPlugin.php +++ b/apps/dav/lib/DAV/ViewOnlyPlugin.php @@ -24,22 +24,24 @@ use OCA\DAV\Connector\Sabre\Exception\Forbidden; use OCA\DAV\Connector\Sabre\File as DavFile; use OCA\Files_Versions\Sabre\VersionFile; +use OCP\Files\Folder; use OCP\Files\NotFoundException; -use Psr\Log\LoggerInterface; +use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; use Sabre\HTTP\RequestInterface; -use Sabre\DAV\Exception\NotFound; /** * Sabre plugin for restricting file share receiver download: */ class ViewOnlyPlugin extends ServerPlugin { private ?Server $server = null; - private LoggerInterface $logger; + private ?Folder $userFolder; - public function __construct(LoggerInterface $logger) { - $this->logger = $logger; + public function __construct( + ?Folder $userFolder + ) { + $this->userFolder = $userFolder; } /** @@ -74,8 +76,18 @@ public function checkViewOnly(RequestInterface $request): bool { if ($davNode instanceof DavFile) { // Restrict view-only to nodes which are shared $node = $davNode->getNode(); - } else if ($davNode instanceof VersionFile) { + } elseif ($davNode instanceof VersionFile) { $node = $davNode->getVersion()->getSourceFile(); + $currentUserId = $this->userFolder->getOwner()->getUID(); + // The version source file is relative to the owner storage. + // But we need the node from the current user perspective. + if ($node->getOwner()->getUID() !== $currentUserId) { + $nodes = $this->userFolder->getById($node->getId()); + $node = array_pop($nodes); + if (!$node) { + throw new NotFoundException("Version file not accessible by current user"); + } + } } else { return true; } diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 670c91c76d728..3457de3afa82d 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -232,7 +232,7 @@ public function __construct(IRequest $request, string $baseUri) { // Allow view-only plugin for webdav requests $this->server->addPlugin(new ViewOnlyPlugin( - \OC::$server->get(LoggerInterface::class) + \OC::$server->getUserFolder() )); if (BrowserErrorPagePlugin::isBrowserRequest($request)) { diff --git a/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php b/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php index e0f6f1302a5ab..a00a04d147f17 100644 --- a/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php +++ b/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php @@ -26,10 +26,11 @@ use OCA\Files_Versions\Versions\IVersion; use OCA\Files_Versions\Sabre\VersionFile; use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\Storage\IStorage; +use OCP\IUser; use OCP\Share\IAttributes; use OCP\Share\IShare; -use Psr\Log\LoggerInterface; use Sabre\DAV\Server; use Sabre\DAV\Tree; use Test\TestCase; @@ -43,10 +44,13 @@ class ViewOnlyPluginTest extends TestCase { private $tree; /** @var RequestInterface | \PHPUnit\Framework\MockObject\MockObject */ private $request; + /** @var Folder | \PHPUnit\Framework\MockObject\MockObject */ + private $userFolder; public function setUp(): void { + $this->userFolder = $this->createMock(Folder::class); $this->plugin = new ViewOnlyPlugin( - $this->createMock(LoggerInterface::class) + $this->userFolder, ); $this->request = $this->createMock(RequestInterface::class); $this->tree = $this->createMock(Tree::class); @@ -111,6 +115,26 @@ public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanD $davNode->expects($this->once()) ->method('getVersion') ->willReturn($version); + + $currentUser = $this->createMock(IUser::class); + $currentUser->expects($this->once()) + ->method('getUID') + ->willReturn('alice'); + $nodeInfo->expects($this->once()) + ->method('getOwner') + ->willReturn($currentUser); + + $nodeInfo = $this->createMock(File::class); + $owner = $this->createMock(IUser::class); + $owner->expects($this->once()) + ->method('getUID') + ->willReturn('bob'); + $this->userFolder->expects($this->once()) + ->method('getById') + ->willReturn([$nodeInfo]); + $this->userFolder->expects($this->once()) + ->method('getOwner') + ->willReturn($owner); } else { $davPath = 'files/path/to/file.odt'; $davNode = $this->createMock(DavFile::class); diff --git a/apps/dav/tests/unit/ServerTest.php b/apps/dav/tests/unit/ServerTest.php index 8cdd52f574575..a75b8fc2053de 100644 --- a/apps/dav/tests/unit/ServerTest.php +++ b/apps/dav/tests/unit/ServerTest.php @@ -45,6 +45,7 @@ public function test($uri, array $plugins) { /** @var IRequest | \PHPUnit\Framework\MockObject\MockObject $r */ $r = $this->createMock(IRequest::class); $r->expects($this->any())->method('getRequestUri')->willReturn($uri); + $this->loginAsUser('admin'); $s = new Server($r, '/'); $this->assertNotNull($s->server); foreach ($plugins as $plugin) {