mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 00:32:29 -04:00
feat: implement authoritative mount provider for share provider
Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
parent
563ff9f431
commit
d718d68e26
3 changed files with 38 additions and 21 deletions
|
|
@ -15,6 +15,7 @@ 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;
|
||||
|
|
@ -36,50 +37,64 @@ class SharesUpdatedListener implements IEventListener {
|
|||
private readonly IUserMountCache $userMountCache,
|
||||
private readonly MountProvider $shareMountProvider,
|
||||
private readonly ShareTargetValidator $shareTargetValidator,
|
||||
private readonly IStorageFactory $storageFactory,
|
||||
) {
|
||||
}
|
||||
public function handle(Event $event): void {
|
||||
if ($event instanceof UserShareAccessUpdatedEvent) {
|
||||
foreach ($event->getUsers() as $user) {
|
||||
$this->updateForUser($user);
|
||||
$this->updateForUser($user, true);
|
||||
}
|
||||
}
|
||||
if ($event instanceof UserAddedEvent || $event instanceof UserRemovedEvent) {
|
||||
$this->updateForUser($event->getUser());
|
||||
$this->updateForUser($event->getUser(), true);
|
||||
}
|
||||
if (
|
||||
$event instanceof ShareCreatedEvent
|
||||
|| $event instanceof BeforeShareDeletedEvent
|
||||
|| $event instanceof ShareTransferredEvent
|
||||
) {
|
||||
foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) {
|
||||
$this->updateForUser($user);
|
||||
$this->updateForUser($user, true);
|
||||
}
|
||||
}
|
||||
if ($event instanceof BeforeShareDeletedEvent) {
|
||||
foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) {
|
||||
$this->updateForUser($user, false, [$event->getShare()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function updateForUser(IUser $user): void {
|
||||
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);
|
||||
$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])) {
|
||||
$this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares);
|
||||
$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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use InvalidArgumentException;
|
|||
use OC\Files\View;
|
||||
use OCA\Files_Sharing\Event\ShareMountedEvent;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Files\Config\IAuthoritativeMountProvider;
|
||||
use OCP\Files\Config\IMountProvider;
|
||||
use OCP\Files\Config\IPartialMountProvider;
|
||||
use OCP\Files\Mount\IMountManager;
|
||||
|
|
@ -27,7 +28,7 @@ use Psr\Log\LoggerInterface;
|
|||
|
||||
use function count;
|
||||
|
||||
class MountProvider implements IMountProvider, IPartialMountProvider {
|
||||
class MountProvider implements IMountProvider, IAuthoritativeMountProvider, IPartialMountProvider {
|
||||
|
||||
/**
|
||||
* @param IConfig $config
|
||||
|
|
@ -58,9 +59,10 @@ class MountProvider implements IMountProvider, IPartialMountProvider {
|
|||
|
||||
/**
|
||||
* @param IUser $user
|
||||
* @param list<IShare> $excludeShares
|
||||
* @return list<array{IShare, array<IShare>}> Tuple of [superShare, groupedShares]
|
||||
*/
|
||||
public function getSuperSharesForUser(IUser $user): array {
|
||||
public function getSuperSharesForUser(IUser $user, array $excludeShares = []): array {
|
||||
$userId = $user->getUID();
|
||||
$shares = $this->mergeIterables(
|
||||
$this->shareManager->getSharedWith($userId, IShare::TYPE_USER, null, -1),
|
||||
|
|
@ -70,7 +72,8 @@ class MountProvider implements IMountProvider, IPartialMountProvider {
|
|||
$this->shareManager->getSharedWith($userId, IShare::TYPE_DECK, null, -1),
|
||||
);
|
||||
|
||||
$shares = $this->filterShares($shares, $userId);
|
||||
$excludeShareIds = array_map(fn (IShare $share) => $share->getFullId(), $excludeShares);
|
||||
$shares = $this->filterShares($shares, $userId, $excludeShareIds);
|
||||
return $this->buildSuperShares($shares, $user);
|
||||
}
|
||||
|
||||
|
|
@ -292,12 +295,6 @@ class MountProvider implements IMountProvider, IPartialMountProvider {
|
|||
}
|
||||
|
||||
$shareId = (int)$parentShare->getId();
|
||||
$absMountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/';
|
||||
|
||||
// after the mountpoint is verified for the first time, only new mountpoints (e.g. groupfolders can overwrite the target)
|
||||
if ($shareId > $maxValidatedShare || isset($allMounts[$absMountPoint])) {
|
||||
$this->shareTargetValidator->verifyMountPoint($user, $parentShare, $allMounts, $groupedShares);
|
||||
}
|
||||
|
||||
$mount = new SharedMount(
|
||||
'\OCA\Files_Sharing\SharedStorage',
|
||||
|
|
@ -347,14 +344,16 @@ class MountProvider implements IMountProvider, IPartialMountProvider {
|
|||
* user has no permissions.
|
||||
*
|
||||
* @param iterable<IShare> $shares
|
||||
* @param list<string> $excludeShareIds
|
||||
* @return iterable<IShare>
|
||||
*/
|
||||
private function filterShares(iterable $shares, string $userId): iterable {
|
||||
private function filterShares(iterable $shares, string $userId, array $excludeShareIds = []): iterable {
|
||||
foreach ($shares as $share) {
|
||||
if (
|
||||
$share->getPermissions() > 0
|
||||
&& $share->getShareOwner() !== $userId
|
||||
&& $share->getSharedBy() !== $userId
|
||||
&& !in_array($share->getFullId(), $excludeShareIds)
|
||||
) {
|
||||
yield $share;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ namespace OCA\Files_Sharing\Repair;
|
|||
use OC\Files\SetupManager;
|
||||
use OCA\Files_Sharing\ShareTargetValidator;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\Files\Config\ICachedMountInfo;
|
||||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\Files\IRootFolder;
|
||||
use OCP\Files\Mount\IMountManager;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\IDBConnection;
|
||||
|
|
@ -42,7 +43,7 @@ class CleanupShareTarget implements IRepairStep {
|
|||
private readonly ShareTargetValidator $shareTargetValidator,
|
||||
private readonly IUserManager $userManager,
|
||||
private readonly SetupManager $setupManager,
|
||||
private readonly IMountManager $mountManager,
|
||||
private readonly IUserMountCache $userMountCache,
|
||||
private readonly IRootFolder $rootFolder,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly ICacheFactory $cacheFactory,
|
||||
|
|
@ -85,7 +86,9 @@ class CleanupShareTarget implements IRepairStep {
|
|||
|
||||
$this->setupManager->tearDown();
|
||||
$this->setupManager->setupForUser($recipient);
|
||||
$userMounts = $this->mountManager->getAll();
|
||||
$mounts = $this->userMountCache->getMountsForUser($recipient);
|
||||
$mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $mounts);
|
||||
$userMounts = array_combine($mountPoints, $mounts);
|
||||
$userFolder = $this->rootFolder->getUserFolder($recipient->getUID());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue