mirror of
https://github.com/nextcloud/server.git
synced 2026-02-27 18:37:17 +01:00
chore: move share recipient validation logic to a separate class
Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
@@ -98,6 +98,7 @@ return array(
|
||||
'OCA\\Files_Sharing\\Settings\\Personal' => $baseDir . '/../lib/Settings/Personal.php',
|
||||
'OCA\\Files_Sharing\\ShareBackend\\File' => $baseDir . '/../lib/ShareBackend/File.php',
|
||||
'OCA\\Files_Sharing\\ShareBackend\\Folder' => $baseDir . '/../lib/ShareBackend/Folder.php',
|
||||
'OCA\\Files_Sharing\\ShareRecipientUpdater' => $baseDir . '/../lib/ShareRecipientUpdater.php',
|
||||
'OCA\\Files_Sharing\\ShareTargetValidator' => $baseDir . '/../lib/ShareTargetValidator.php',
|
||||
'OCA\\Files_Sharing\\SharedMount' => $baseDir . '/../lib/SharedMount.php',
|
||||
'OCA\\Files_Sharing\\SharedStorage' => $baseDir . '/../lib/SharedStorage.php',
|
||||
|
||||
@@ -113,6 +113,7 @@ class ComposerStaticInitFiles_Sharing
|
||||
'OCA\\Files_Sharing\\Settings\\Personal' => __DIR__ . '/..' . '/../lib/Settings/Personal.php',
|
||||
'OCA\\Files_Sharing\\ShareBackend\\File' => __DIR__ . '/..' . '/../lib/ShareBackend/File.php',
|
||||
'OCA\\Files_Sharing\\ShareBackend\\Folder' => __DIR__ . '/..' . '/../lib/ShareBackend/Folder.php',
|
||||
'OCA\\Files_Sharing\\ShareRecipientUpdater' => __DIR__ . '/..' . '/../lib/ShareRecipientUpdater.php',
|
||||
'OCA\\Files_Sharing\\ShareTargetValidator' => __DIR__ . '/..' . '/../lib/ShareTargetValidator.php',
|
||||
'OCA\\Files_Sharing\\SharedMount' => __DIR__ . '/..' . '/../lib/SharedMount.php',
|
||||
'OCA\\Files_Sharing\\SharedStorage' => __DIR__ . '/..' . '/../lib/SharedStorage.php',
|
||||
|
||||
@@ -8,23 +8,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace OCA\Files_Sharing\Listener;
|
||||
|
||||
use OC\Files\FileInfo;
|
||||
use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent;
|
||||
use OCA\Files_Sharing\MountProvider;
|
||||
use OCA\Files_Sharing\ShareTargetValidator;
|
||||
use OCA\Files_Sharing\ShareRecipientUpdater;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
use OCP\Files\Config\ICachedMountInfo;
|
||||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\Files\Storage\IStorageFactory;
|
||||
use OCP\Group\Events\UserAddedEvent;
|
||||
use OCP\Group\Events\UserRemovedEvent;
|
||||
use OCP\IUser;
|
||||
use OCP\Share\Events\BeforeShareDeletedEvent;
|
||||
use OCP\Share\Events\ShareCreatedEvent;
|
||||
use OCP\Share\Events\ShareTransferredEvent;
|
||||
use OCP\Share\IManager;
|
||||
use OCP\Share\IShare;
|
||||
|
||||
/**
|
||||
* Listen to various events that can change what shares a user has access to
|
||||
@@ -32,31 +25,26 @@ use OCP\Share\IShare;
|
||||
* @template-implements IEventListener<UserAddedEvent|UserRemovedEvent|ShareCreatedEvent|ShareTransferredEvent|BeforeShareDeletedEvent|UserShareAccessUpdatedEvent>
|
||||
*/
|
||||
class SharesUpdatedListener implements IEventListener {
|
||||
private array $inUpdate = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly IManager $shareManager,
|
||||
private readonly IUserMountCache $userMountCache,
|
||||
private readonly MountProvider $shareMountProvider,
|
||||
private readonly ShareTargetValidator $shareTargetValidator,
|
||||
private readonly IStorageFactory $storageFactory,
|
||||
private readonly ShareRecipientUpdater $shareUpdater,
|
||||
) {
|
||||
}
|
||||
public function handle(Event $event): void {
|
||||
if ($event instanceof UserShareAccessUpdatedEvent) {
|
||||
foreach ($event->getUsers() as $user) {
|
||||
$this->updateForUser($user, true);
|
||||
$this->shareUpdater->updateForUser($user, true);
|
||||
}
|
||||
}
|
||||
if ($event instanceof UserAddedEvent || $event instanceof UserRemovedEvent) {
|
||||
$this->updateForUser($event->getUser(), true);
|
||||
$this->shareUpdater->updateForUser($event->getUser(), true);
|
||||
}
|
||||
if ($event instanceof ShareCreatedEvent || $event instanceof ShareTransferredEvent) {
|
||||
$share = $event->getShare();
|
||||
$shareTarget = $share->getTarget();
|
||||
foreach ($this->shareManager->getUsersForShare($share) as $user) {
|
||||
if ($share->getSharedBy() !== $user->getUID()) {
|
||||
$this->updateForShare($user, $share);
|
||||
$this->shareUpdater->updateForShare($user, $share);
|
||||
// Share target validation might have changed the target, restore it for the next user
|
||||
$share->setTarget($shareTarget);
|
||||
}
|
||||
@@ -64,57 +52,8 @@ class SharesUpdatedListener implements IEventListener {
|
||||
}
|
||||
if ($event instanceof BeforeShareDeletedEvent) {
|
||||
foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) {
|
||||
$this->updateForUser($user, false, [$event->getShare()]);
|
||||
$this->shareManager->updateForUser($user, false, [$event->getShare()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function updateForUser(IUser $user, bool $verifyMountPoints, array $ignoreShares = []): void {
|
||||
// prevent recursion
|
||||
if (isset($this->inUpdate[$user->getUID()])) {
|
||||
return;
|
||||
}
|
||||
$this->inUpdate[$user->getUID()] = true;
|
||||
$cachedMounts = $this->userMountCache->getMountsForUser($user);
|
||||
$shareMounts = array_filter($cachedMounts, fn (ICachedMountInfo $mount) => $mount->getMountProvider() === MountProvider::class);
|
||||
$mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $cachedMounts);
|
||||
$mountsByPath = array_combine($mountPoints, $cachedMounts);
|
||||
|
||||
$shares = $this->shareMountProvider->getSuperSharesForUser($user, $ignoreShares);
|
||||
|
||||
$mountsChanged = count($shares) !== count($shareMounts);
|
||||
foreach ($shares as &$share) {
|
||||
[$parentShare, $groupedShares] = $share;
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/';
|
||||
$mountKey = $parentShare->getNodeId() . '::' . $mountPoint;
|
||||
if (!isset($cachedMounts[$mountKey])) {
|
||||
$mountsChanged = true;
|
||||
if ($verifyMountPoints) {
|
||||
$this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mountsChanged) {
|
||||
$newMounts = $this->shareMountProvider->getMountsFromSuperShares($user, $shares, $this->storageFactory);
|
||||
$this->userMountCache->registerMounts($user, $newMounts, [MountProvider::class]);
|
||||
}
|
||||
|
||||
unset($this->inUpdate[$user->getUID()]);
|
||||
}
|
||||
|
||||
private function updateForShare(IUser $user, IShare $share): void {
|
||||
$cachedMounts = $this->userMountCache->getMountsForUser($user);
|
||||
$mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $cachedMounts);
|
||||
$mountsByPath = array_combine($mountPoints, $cachedMounts);
|
||||
|
||||
$target = $this->shareTargetValidator->verifyMountPoint($user, $share, $mountsByPath, [$share]);
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($target, '/') . '/';
|
||||
|
||||
$fileInfo = $share->getNode();
|
||||
if (!$fileInfo instanceof FileInfo) {
|
||||
throw new \Exception("share node is the wrong fileinfo");
|
||||
}
|
||||
$this->userMountCache->addMount($user, $mountPoint, $fileInfo->getData(), MountProvider::class);
|
||||
}
|
||||
}
|
||||
|
||||
86
apps/files_sharing/lib/ShareRecipientUpdater.php
Normal file
86
apps/files_sharing/lib/ShareRecipientUpdater.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Sharing;
|
||||
|
||||
use OC\Files\FileInfo;
|
||||
use OCP\Files\Config\ICachedMountInfo;
|
||||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\Files\Storage\IStorageFactory;
|
||||
use OCP\IUser;
|
||||
use OCP\Share\IShare;
|
||||
|
||||
class ShareRecipientUpdater {
|
||||
private array $inUpdate = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly IUserMountCache $userMountCache,
|
||||
private readonly MountProvider $shareMountProvider,
|
||||
private readonly ShareTargetValidator $shareTargetValidator,
|
||||
private readonly IStorageFactory $storageFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate all received shares for a user
|
||||
*/
|
||||
public function updateForUser(IUser $user, bool $verifyMountPoints = true, array $ignoreShares = []): void {
|
||||
// prevent recursion
|
||||
if (isset($this->inUpdate[$user->getUID()])) {
|
||||
return;
|
||||
}
|
||||
$this->inUpdate[$user->getUID()] = true;
|
||||
|
||||
$cachedMounts = $this->userMountCache->getMountsForUser($user);
|
||||
$shareMounts = array_filter($cachedMounts, fn (ICachedMountInfo $mount) => $mount->getMountProvider() === MountProvider::class);
|
||||
$mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $cachedMounts);
|
||||
$mountsByPath = array_combine($mountPoints, $cachedMounts);
|
||||
|
||||
$shares = $this->shareMountProvider->getSuperSharesForUser($user, $ignoreShares);
|
||||
|
||||
// the share mounts have changed if either the number of shares doesn't matched the number of share mounts
|
||||
// or there is a share for which we don't have a mount yet.
|
||||
$mountsChanged = count($shares) !== count($shareMounts);
|
||||
foreach ($shares as &$share) {
|
||||
[$parentShare, $groupedShares] = $share;
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/';
|
||||
$mountKey = $parentShare->getNodeId() . '::' . $mountPoint;
|
||||
if (!isset($cachedMounts[$mountKey])) {
|
||||
$mountsChanged = true;
|
||||
if ($verifyMountPoints) {
|
||||
$this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mountsChanged) {
|
||||
$newMounts = $this->shareMountProvider->getMountsFromSuperShares($user, $shares, $this->storageFactory);
|
||||
$this->userMountCache->registerMounts($user, $newMounts, [MountProvider::class]);
|
||||
}
|
||||
|
||||
unset($this->inUpdate[$user->getUID()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a single received share for a user
|
||||
*/
|
||||
public function updateForShare(IUser $user, IShare $share): void {
|
||||
$cachedMounts = $this->userMountCache->getMountsForUser($user);
|
||||
$mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $cachedMounts);
|
||||
$mountsByPath = array_combine($mountPoints, $cachedMounts);
|
||||
|
||||
$target = $this->shareTargetValidator->verifyMountPoint($user, $share, $mountsByPath, [$share]);
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($target, '/') . '/';
|
||||
|
||||
$fileInfo = $share->getNode();
|
||||
if (!$fileInfo instanceof FileInfo) {
|
||||
throw new \Exception('share node is the wrong fileinfo');
|
||||
}
|
||||
$this->userMountCache->addMount($user, $mountPoint, $fileInfo->getData(), MountProvider::class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user