diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-09-28 22:16:42 +0200 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-09-29 13:29:04 +0200 |
commit | e0c00af3bf63b41d4c47a8d0ae8ae137b05d5fd9 (patch) | |
tree | f52c6a1cd095b704359304a4e568a1e7b881e9c8 | |
parent | a0b2297c536923867ed3f8e489dabe8a278ac0be (diff) | |
download | nextcloud-server-e0c00af3bf63b41d4c47a8d0ae8ae137b05d5fd9.tar.gz nextcloud-server-e0c00af3bf63b41d4c47a8d0ae8ae137b05d5fd9.zip |
fix(dav): Emit `BeforeZipCreatedEvent` when creating folder zip archivefix/bring-back-zip-event
This is required to not break behavior on zip download (apps should be able to react to zip download especially for shares).
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
-rw-r--r-- | apps/dav/lib/Connector/Sabre/ServerFactory.php | 45 | ||||
-rw-r--r-- | apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php | 28 | ||||
-rw-r--r-- | apps/dav/lib/Server.php | 15 | ||||
-rw-r--r-- | lib/public/Files/Events/BeforeZipCreatedEvent.php | 30 |
4 files changed, 71 insertions, 47 deletions
diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index 4235a02831a..617ba60f80d 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -28,39 +28,19 @@ use Psr\Log\LoggerInterface; use Sabre\DAV\Auth\Plugin; class ServerFactory { - private IConfig $config; - private LoggerInterface $logger; - private IDBConnection $databaseConnection; - private IUserSession $userSession; - private IMountManager $mountManager; - private ITagManager $tagManager; - private IRequest $request; - private IPreview $previewManager; - private IEventDispatcher $eventDispatcher; - private IL10N $l10n; public function __construct( - IConfig $config, - LoggerInterface $logger, - IDBConnection $databaseConnection, - IUserSession $userSession, - IMountManager $mountManager, - ITagManager $tagManager, - IRequest $request, - IPreview $previewManager, - IEventDispatcher $eventDispatcher, - IL10N $l10n, + private IConfig $config, + private LoggerInterface $logger, + private IDBConnection $databaseConnection, + private IUserSession $userSession, + private IMountManager $mountManager, + private ITagManager $tagManager, + private IRequest $request, + private IPreview $previewManager, + private IEventDispatcher $eventDispatcher, + private IL10N $l10n, ) { - $this->config = $config; - $this->logger = $logger; - $this->databaseConnection = $databaseConnection; - $this->userSession = $userSession; - $this->mountManager = $mountManager; - $this->tagManager = $tagManager; - $this->request = $request; - $this->previewManager = $previewManager; - $this->eventDispatcher = $eventDispatcher; - $this->l10n = $l10n; } /** @@ -80,7 +60,7 @@ class ServerFactory { // Load plugins $server->addPlugin(new \OCA\DAV\Connector\Sabre\MaintenancePlugin($this->config, $this->l10n)); $server->addPlugin(new BlockLegacyClientPlugin( - \OCP\Server::get(IConfig::class), + $this->config, \OCP\Server::get(ThemingDefaults::class), )); $server->addPlugin(new \OCA\DAV\Connector\Sabre\AnonymousOptionsPlugin()); @@ -90,11 +70,12 @@ class ServerFactory { $server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger)); $server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin()); - $server->addPlugin(new RequestIdHeaderPlugin(\OC::$server->get(IRequest::class))); + $server->addPlugin(new RequestIdHeaderPlugin($this->request)); $server->addPlugin(new ZipFolderPlugin( $objectTree, $this->logger, + $this->eventDispatcher, )); // Some WebDAV clients do require Class 2 WebDAV support (locking), since diff --git a/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php b/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php index a5820f80538..8484dfa1935 100644 --- a/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php +++ b/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php @@ -9,6 +9,9 @@ declare(strict_types=1); namespace OCA\DAV\Connector\Sabre; use OC\Streamer; +use OCA\DAV\Connector\Sabre\Exception\Forbidden; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Events\BeforeZipCreatedEvent; use OCP\Files\File as NcFile; use OCP\Files\Folder as NcFolder; use OCP\Files\Node as NcNode; @@ -37,6 +40,7 @@ class ZipFolderPlugin extends ServerPlugin { public function __construct( private Tree $tree, private LoggerInterface $logger, + private IEventDispatcher $eventDispatcher, ) { } @@ -114,17 +118,33 @@ class ZipFolderPlugin extends ServerPlugin { if ($filesParam !== '') { $files = json_decode($filesParam); if (!is_array($files)) { - if (!is_string($files)) { + $files = [$files]; + } + + foreach ($files as $file) { + if (!is_string($file)) { + // we log this as this means either we - or an app - have a bug somewhere or a user is trying invalid things + $this->logger->notice('Invalid files filter parameter for ZipFolderPlugin', ['filter' => $filesParam]); // no valid parameter so continue with Sabre behavior - $this->logger->debug('Invalid files filter parameter for ZipFolderPlugin', ['filter' => $filesParam]); return null; } - - $files = [$files]; } } $folder = $node->getNode(); + $event = new BeforeZipCreatedEvent($folder, $files); + $this->eventDispatcher->dispatchTyped($event); + if ((!$event->isSuccessful()) || $event->getErrorMessage() !== null) { + $errorMessage = $event->getErrorMessage(); + if ($errorMessage === null) { + // Not allowed to download but also no explaining error + // so we abort the ZIP creation and fall back to Sabre default behavior. + return null; + } + // Downloading was denied by an app + throw new Forbidden($errorMessage); + } + $content = empty($files) ? $folder->getDirectoryListing() : []; foreach ($files as $path) { $child = $node->getChild($path); diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 69f05395cb5..4bfc8019218 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -86,9 +86,9 @@ class Server { $this->request = $request; $this->baseUri = $baseUri; - $logger = \OC::$server->get(LoggerInterface::class); - /** @var IEventDispatcher $dispatcher */ - $dispatcher = \OC::$server->get(IEventDispatcher::class); + + $logger = \OCP\Server::get(LoggerInterface::class); + $eventDispatcher = \OCP\Server::get(IEventDispatcher::class); $root = new RootCollection(); $this->server = new \OCA\DAV\Connector\Sabre\Server(new CachingTree($root)); @@ -123,10 +123,10 @@ class Server { // allow setup of additional auth backends $event = new SabrePluginEvent($this->server); - $dispatcher->dispatch('OCA\DAV\Connector\Sabre::authInit', $event); + $eventDispatcher->dispatch('OCA\DAV\Connector\Sabre::authInit', $event); $newAuthEvent = new SabrePluginAuthInitEvent($this->server); - $dispatcher->dispatchTyped($newAuthEvent); + $eventDispatcher->dispatchTyped($newAuthEvent); $bearerAuthBackend = new BearerAuth( \OC::$server->getUserSession(), @@ -213,12 +213,13 @@ class Server { $this->server->addPlugin(new ZipFolderPlugin( $this->server->tree, $logger, + $eventDispatcher, )); // allow setup of additional plugins - $dispatcher->dispatch('OCA\DAV\Connector\Sabre::addPlugin', $event); + $eventDispatcher->dispatch('OCA\DAV\Connector\Sabre::addPlugin', $event); $typedEvent = new SabrePluginAddEvent($this->server); - $dispatcher->dispatchTyped($typedEvent); + $eventDispatcher->dispatchTyped($typedEvent); // Some WebDAV clients do require Class 2 WebDAV support (locking), since // we do not provide locking we emulate it using a fake locking plugin. diff --git a/lib/public/Files/Events/BeforeZipCreatedEvent.php b/lib/public/Files/Events/BeforeZipCreatedEvent.php index b55b36d3968..0363d385d36 100644 --- a/lib/public/Files/Events/BeforeZipCreatedEvent.php +++ b/lib/public/Files/Events/BeforeZipCreatedEvent.php @@ -10,23 +10,45 @@ declare(strict_types=1); namespace OCP\Files\Events; use OCP\EventDispatcher\Event; +use OCP\Files\Folder; /** + * This event is triggered before a archive is created when a user requested + * downloading a folder or multiple files. + * + * By setting `successful` to false the tar creation can be aborted and the download denied. + * * @since 25.0.0 */ class BeforeZipCreatedEvent extends Event { private string $directory; - private array $files; private bool $successful = true; private ?string $errorMessage = null; + private ?Folder $folder = null; /** + * @param list<string> $files * @since 25.0.0 + * @since 31.0.0 support `OCP\Files\Folder` as `$directory` parameter - passing a string is deprecated now */ - public function __construct(string $directory, array $files) { + public function __construct( + string|Folder $directory, + private array $files, + ) { parent::__construct(); - $this->directory = $directory; - $this->files = $files; + if ($directory instanceof Folder) { + $this->directory = $directory->getPath(); + $this->folder = $directory; + } else { + $this->directory = $directory; + } + } + + /** + * @since 31.0.0 + */ + public function getFolder(): ?Folder { + return $this->folder; } /** |