Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable28] [stable29] fix: promote re-shares when deleting the parent share #49931

Open
wants to merge 11 commits into
base: stable28
Choose a base branch
from
Open
20 changes: 10 additions & 10 deletions apps/files/lib/Service/OwnershipTransferService.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,6 @@ public function transfer(
$output
);

$destinationPath = $finalTarget . '/' . $path;
// restore the shares
$this->restoreShares(
$sourceUid,
$destinationUid,
$destinationPath,
$shares,
$output
);

// transfer the incoming shares
if ($transferIncomingShares === true) {
$sourceShares = $this->collectIncomingShares(
Expand All @@ -210,6 +200,16 @@ public function transfer(
$move
);
}

$destinationPath = $finalTarget . '/' . $path;
// restore the shares
$this->restoreShares(
$sourceUid,
$destinationUid,
$destinationPath,
$shares,
$output
);
}

private function walkFiles(View $view, $path, Closure $callBack) {
Expand Down
87 changes: 87 additions & 0 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
use OCP\Files\IRootFolder;
use OCP\Files\Mount\IMountManager;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\HintException;
use OCP\IConfig;
use OCP\IDateTimeZone;
Expand Down Expand Up @@ -1155,6 +1156,89 @@ protected function deleteChildren(IShare $share) {
return $deletedShares;
}

/** Promote re-shares into direct shares so that target user keeps access */
protected function promoteReshares(IShare $share): void {
try {
$node = $share->getNode();
} catch (NotFoundException) {
/* Skip if node not found */
return;
}

$userIds = [];

if ($share->getShareType() === IShare::TYPE_USER) {
$userIds[] = $share->getSharedWith();
} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
$group = $this->groupManager->get($share->getSharedWith());
$users = $group?->getUsers() ?? [];

foreach ($users as $user) {
/* Skip share owner */
if ($user->getUID() === $share->getShareOwner() || $user->getUID() === $share->getSharedBy()) {
continue;
}
$userIds[] = $user->getUID();
}
} else {
/* We only support user and group shares */
return;
}

$reshareRecords = [];
$shareTypes = [
IShare::TYPE_GROUP,
IShare::TYPE_USER,
IShare::TYPE_LINK,
IShare::TYPE_REMOTE,
IShare::TYPE_EMAIL,
];

foreach ($userIds as $userId) {
foreach ($shareTypes as $shareType) {
$provider = $this->factory->getProviderForType($shareType);
if ($node instanceof Folder) {
/* We need to get all shares by this user to get subshares */
$shares = $provider->getSharesBy($userId, $shareType, null, false, -1, 0);

foreach ($shares as $share) {
try {
$path = $share->getNode()->getPath();
} catch (NotFoundException) {
/* Ignore share of non-existing node */
continue;
}
if ($node->getRelativePath($path) !== null) {
/* If relative path is not null it means the shared node is the same or in a subfolder */
$reshareRecords[] = $share;
}
}
} else {
$shares = $provider->getSharesBy($userId, $shareType, $node, false, -1, 0);
foreach ($shares as $child) {
$reshareRecords[] = $child;
}
}
}
}

foreach ($reshareRecords as $child) {
try {
/* Check if the share is still valid (means the resharer still has access to the file through another mean) */
$this->generalCreateChecks($child);
} catch (GenericShareException $e) {
/* The check is invalid, promote it to a direct share from the sharer of parent share */
$this->logger->debug('Promote reshare because of exception ' . $e->getMessage(), ['exception' => $e, 'fullId' => $child->getFullId()]);
try {
$child->setSharedBy($share->getSharedBy());
$this->updateShare($child);
} catch (GenericShareException|\InvalidArgumentException $e) {
$this->logger->warning('Failed to promote reshare because of exception ' . $e->getMessage(), ['exception' => $e, 'fullId' => $child->getFullId()]);
}
}
}
}

/**
* Delete a share
*
Expand All @@ -1179,6 +1263,9 @@ public function deleteShare(IShare $share) {
$provider->delete($share);

$this->dispatcher->dispatchTyped(new ShareDeletedEvent($share));

// Promote reshares of the deleted share
$this->promoteReshares($share);
}


Expand Down
Loading
Loading