From ee70b113a8f9e9f36b18ce63ce0a0a92d6567894 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 15 Apr 2026 21:50:24 +0200 Subject: [PATCH] fix: redact share token if share has more permissions than the current user Signed-off-by: Robin Appelman --- .../lib/Controller/ShareAPIController.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index 0f1ad3bd5d5..25c4ca1c72f 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -239,6 +239,10 @@ class ShareAPIController extends OCSController { $result['expiration'] = $expiration->format('Y-m-d H:i:s'); } + $currentUserPermissions = $recipientNode?->getPermissions() ?? Constants::PERMISSION_ALL; + $userHasEnoughPermissions = ($currentUserPermissions & $share->getPermissions()) === $share->getPermissions(); + $token = $userHasEnoughPermissions ? $share->getToken() : null; + if ($share->getShareType() === IShare::TYPE_USER) { $sharedWith = $this->userManager->get($share->getSharedWith()); $result['share_with'] = $share->getSharedWith(); @@ -264,6 +268,7 @@ class ShareAPIController extends OCSController { $result['share_with'] = $share->getSharedWith(); $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith(); } elseif ($share->getShareType() === IShare::TYPE_LINK) { + $url = $token ? $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]) : null; // "share_with" and "share_with_displayname" for passwords of link // shares was deprecated in Nextcloud 15, use "password" instead. @@ -274,23 +279,23 @@ class ShareAPIController extends OCSController { $result['send_password_by_talk'] = $share->getSendPasswordByTalk(); - $result['token'] = $share->getToken(); - $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]); + $result['token'] = $token; + $result['url'] = $url; } elseif ($share->getShareType() === IShare::TYPE_REMOTE) { $result['share_with'] = $share->getSharedWith(); $result['share_with_displayname'] = $this->getCachedFederatedDisplayName($share->getSharedWith()); - $result['token'] = $share->getToken(); + $result['token'] = $token; } elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) { $result['share_with'] = $share->getSharedWith(); $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD'); - $result['token'] = $share->getToken(); + $result['token'] = $token; } elseif ($share->getShareType() === IShare::TYPE_EMAIL) { $result['share_with'] = $share->getSharedWith(); $result['password'] = $share->getPassword(); $result['password_expiration_time'] = $share->getPasswordExpirationTime() !== null ? $share->getPasswordExpirationTime()->format(\DateTime::ATOM) : null; $result['send_password_by_talk'] = $share->getSendPasswordByTalk(); $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL'); - $result['token'] = $share->getToken(); + $result['token'] = $token; } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) { // getSharedWith() returns either "name (type, owner)" or // "name (type, owner) [id]", depending on the Teams app version.