Merge pull request #48438 from nextcloud/fix/bring-back-zip-event

fix(dav): Emit `BeforeZipCreatedEvent` when creating folder zip archive
pull/48623/head
Ferdinand Thiessen 2024-10-07 11:58:34 +07:00 committed by GitHub
commit 02f3c88d73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 71 additions and 47 deletions

@ -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

@ -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);

@ -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.

@ -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;
}
/**