Skip to content

Commit 7cc76d8

Browse files
Merge pull request #49931 from nextcloud/backport/49927/stable28
[stable28] fix: promote re-shares when deleting the parent share
2 parents 571f108 + 4c10a79 commit 7cc76d8

File tree

3 files changed

+289
-15
lines changed

3 files changed

+289
-15
lines changed

apps/files/lib/Service/OwnershipTransferService.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,6 @@ public function transfer(
176176
$output
177177
);
178178

179-
$destinationPath = $finalTarget . '/' . $path;
180-
// restore the shares
181-
$this->restoreShares(
182-
$sourceUid,
183-
$destinationUid,
184-
$destinationPath,
185-
$shares,
186-
$output
187-
);
188-
189179
// transfer the incoming shares
190180
if ($transferIncomingShares === true) {
191181
$sourceShares = $this->collectIncomingShares(
@@ -210,6 +200,16 @@ public function transfer(
210200
$move
211201
);
212202
}
203+
204+
$destinationPath = $finalTarget . '/' . $path;
205+
// restore the shares
206+
$this->restoreShares(
207+
$sourceUid,
208+
$destinationUid,
209+
$destinationPath,
210+
$shares,
211+
$output
212+
);
213213
}
214214

215215
private function walkFiles(View $view, $path, Closure $callBack) {

lib/private/Share20/Manager.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
use OCP\Files\IRootFolder;
5353
use OCP\Files\Mount\IMountManager;
5454
use OCP\Files\Node;
55+
use OCP\Files\NotFoundException;
5556
use OCP\HintException;
5657
use OCP\IConfig;
5758
use OCP\IDateTimeZone;
@@ -1155,6 +1156,89 @@ protected function deleteChildren(IShare $share) {
11551156
return $deletedShares;
11561157
}
11571158

1159+
/** Promote re-shares into direct shares so that target user keeps access */
1160+
protected function promoteReshares(IShare $share): void {
1161+
try {
1162+
$node = $share->getNode();
1163+
} catch (NotFoundException) {
1164+
/* Skip if node not found */
1165+
return;
1166+
}
1167+
1168+
$userIds = [];
1169+
1170+
if ($share->getShareType() === IShare::TYPE_USER) {
1171+
$userIds[] = $share->getSharedWith();
1172+
} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
1173+
$group = $this->groupManager->get($share->getSharedWith());
1174+
$users = $group?->getUsers() ?? [];
1175+
1176+
foreach ($users as $user) {
1177+
/* Skip share owner */
1178+
if ($user->getUID() === $share->getShareOwner() || $user->getUID() === $share->getSharedBy()) {
1179+
continue;
1180+
}
1181+
$userIds[] = $user->getUID();
1182+
}
1183+
} else {
1184+
/* We only support user and group shares */
1185+
return;
1186+
}
1187+
1188+
$reshareRecords = [];
1189+
$shareTypes = [
1190+
IShare::TYPE_GROUP,
1191+
IShare::TYPE_USER,
1192+
IShare::TYPE_LINK,
1193+
IShare::TYPE_REMOTE,
1194+
IShare::TYPE_EMAIL,
1195+
];
1196+
1197+
foreach ($userIds as $userId) {
1198+
foreach ($shareTypes as $shareType) {
1199+
$provider = $this->factory->getProviderForType($shareType);
1200+
if ($node instanceof Folder) {
1201+
/* We need to get all shares by this user to get subshares */
1202+
$shares = $provider->getSharesBy($userId, $shareType, null, false, -1, 0);
1203+
1204+
foreach ($shares as $share) {
1205+
try {
1206+
$path = $share->getNode()->getPath();
1207+
} catch (NotFoundException) {
1208+
/* Ignore share of non-existing node */
1209+
continue;
1210+
}
1211+
if ($node->getRelativePath($path) !== null) {
1212+
/* If relative path is not null it means the shared node is the same or in a subfolder */
1213+
$reshareRecords[] = $share;
1214+
}
1215+
}
1216+
} else {
1217+
$shares = $provider->getSharesBy($userId, $shareType, $node, false, -1, 0);
1218+
foreach ($shares as $child) {
1219+
$reshareRecords[] = $child;
1220+
}
1221+
}
1222+
}
1223+
}
1224+
1225+
foreach ($reshareRecords as $child) {
1226+
try {
1227+
/* Check if the share is still valid (means the resharer still has access to the file through another mean) */
1228+
$this->generalCreateChecks($child);
1229+
} catch (GenericShareException $e) {
1230+
/* The check is invalid, promote it to a direct share from the sharer of parent share */
1231+
$this->logger->debug('Promote reshare because of exception ' . $e->getMessage(), ['exception' => $e, 'fullId' => $child->getFullId()]);
1232+
try {
1233+
$child->setSharedBy($share->getSharedBy());
1234+
$this->updateShare($child);
1235+
} catch (GenericShareException|\InvalidArgumentException $e) {
1236+
$this->logger->warning('Failed to promote reshare because of exception ' . $e->getMessage(), ['exception' => $e, 'fullId' => $child->getFullId()]);
1237+
}
1238+
}
1239+
}
1240+
}
1241+
11581242
/**
11591243
* Delete a share
11601244
*
@@ -1179,6 +1263,9 @@ public function deleteShare(IShare $share) {
11791263
$provider->delete($share);
11801264

11811265
$this->dispatcher->dispatchTyped(new ShareDeletedEvent($share));
1266+
1267+
// Promote reshares of the deleted share
1268+
$this->promoteReshares($share);
11821269
}
11831270

11841271

0 commit comments

Comments
 (0)