From 7a9c04a27a0564df2e8f805e9b3ce28785d810a5 Mon Sep 17 00:00:00 2001 From: nfebe Date: Thu, 16 Oct 2025 15:34:30 +0200 Subject: [PATCH 1/2] fix(sharing): Allow public share access for everyone When a logged-in user accesses a public share link in the same browser, the system was incorrectly checking if that user's groups were excluded from creating link shares. This caused share not found errors for users in excluded groups, even though public shares should be accessible to anyone with the link. The group exclusion setting (`shareapi_allow_links_exclude_groups`) is intended to restrict share creation, not share access. Public shares are meant to be anonymous and accessible regardless of the viewer identity or group membership. Signed-off-by: nfebe --- lib/private/Share20/Manager.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 4abc3a3f54cad..74bd888fbc764 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -1413,7 +1413,7 @@ public function getShareByToken($token) { } $share = null; try { - if ($this->shareApiAllowLinks()) { + if ($this->shareApiAllowLinks(checkGroupExclusion: false)) { $provider = $this->factory->getProviderForType(IShare::TYPE_LINK); $share = $provider->getShareByToken($token); } @@ -1742,19 +1742,22 @@ public function shareApiEnabled() { /** * Is public link sharing enabled * + * @param bool $checkGroupExclusion Whether to check the current user's group exclusions * @return bool */ - public function shareApiAllowLinks() { + public function shareApiAllowLinks(bool $checkGroupExclusion = true) { if ($this->config->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') { return false; } - $user = $this->userSession->getUser(); - if ($user) { - $excludedGroups = json_decode($this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', '[]')); - if ($excludedGroups) { - $userGroups = $this->groupManager->getUserGroupIds($user); - return !(bool)array_intersect($excludedGroups, $userGroups); + if ($checkGroupExclusion) { + $user = $this->userSession->getUser(); + if ($user) { + $excludedGroups = json_decode($this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', '[]')); + if ($excludedGroups) { + $userGroups = $this->groupManager->getUserGroupIds($user); + return !(bool)array_intersect($excludedGroups, $userGroups); + } } } From 560779d1bef4d6d3163dc61cdf0c5f336972ff55 Mon Sep 17 00:00:00 2001 From: nfebe Date: Fri, 17 Oct 2025 11:21:12 +0200 Subject: [PATCH 2/2] refactor: Separate concerns in link sharing checks Following https://github.com/nextcloud/server/pull/55811 split `shareApiAllowLinks()` into two dedicated methods to improve clarity and separation of concerns: - `isLinkSharingEnabled()`: Checks if link sharing is globally enabled - `canUserCreateLinkShares()`: Checks if a user can create link shares (considers both global settings and group restrictions) The original shareApiAllowLinks() is now deprecated and acts as a wrapper to maintain backward compatibility. --- apps/files_sharing/lib/Capabilities.php | 2 +- lib/private/Share20/Manager.php | 57 ++++++++++++++++++------- lib/public/Share/IManager.php | 20 +++++++++ 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/apps/files_sharing/lib/Capabilities.php b/apps/files_sharing/lib/Capabilities.php index 06aa1271c8f8d..d1b75cd0a99d4 100644 --- a/apps/files_sharing/lib/Capabilities.php +++ b/apps/files_sharing/lib/Capabilities.php @@ -106,7 +106,7 @@ public function getCapabilities() { $res['api_enabled'] = true; $public = []; - $public['enabled'] = $this->shareManager->shareApiAllowLinks(); + $public['enabled'] = $this->shareManager->canUserCreateLinkShares(); if ($public['enabled']) { $public['password'] = []; $public['password']['enforced'] = $this->shareManager->shareApiLinkEnforcePassword(); diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 74bd888fbc764..15a14af5c9f83 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -559,7 +559,7 @@ protected function groupCreateChecks(IShare $share) { */ protected function linkCreateChecks(IShare $share) { // Are link shares allowed? - if (!$this->shareApiAllowLinks()) { + if (!$this->canUserCreateLinkShares()) { throw new \Exception($this->l->t('Link sharing is not allowed')); } @@ -1413,7 +1413,7 @@ public function getShareByToken($token) { } $share = null; try { - if ($this->shareApiAllowLinks(checkGroupExclusion: false)) { + if ($this->isLinkSharingEnabled()) { $provider = $this->factory->getProviderForType(IShare::TYPE_LINK); $share = $provider->getShareByToken($token); } @@ -1740,30 +1740,57 @@ public function shareApiEnabled() { } /** - * Is public link sharing enabled + * Check if public link sharing is enabled globally * - * @param bool $checkGroupExclusion Whether to check the current user's group exclusions * @return bool + * @since 33.0.0 */ - public function shareApiAllowLinks(bool $checkGroupExclusion = true) { - if ($this->config->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') { + public function isLinkSharingEnabled(): bool { + return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes'; + } + + /** + * Check if a specific user can create public link shares + * + * This considers both global settings and user-specific group restrictions + * + * @param string|null $userId The user ID to check, or null for current user + * @return bool + * @since 33.0.0 + */ + public function canUserCreateLinkShares(?string $userId = null): bool { + if (!$this->isLinkSharingEnabled()) { return false; } - if ($checkGroupExclusion) { - $user = $this->userSession->getUser(); - if ($user) { - $excludedGroups = json_decode($this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', '[]')); - if ($excludedGroups) { - $userGroups = $this->groupManager->getUserGroupIds($user); - return !(bool)array_intersect($excludedGroups, $userGroups); - } - } + $user = $userId ? $this->userManager->get($userId) : $this->userSession->getUser(); + if (!$user) { + return true; + } + + $excludedGroups = json_decode($this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', '[]')); + if ($excludedGroups) { + $userGroups = $this->groupManager->getUserGroupIds($user); + return !(bool)array_intersect($excludedGroups, $userGroups); } return true; } + /** + * Is public link sharing enabled + * + * @param bool $checkGroupExclusion Whether to check the current user's group exclusions + * @return bool + * @deprecated 33.0.0 Use isLinkSharingEnabled() or canUserCreateLinkShares() instead + */ + public function shareApiAllowLinks(bool $checkGroupExclusion = true) { + if ($checkGroupExclusion) { + return $this->canUserCreateLinkShares(); + } + return $this->isLinkSharingEnabled(); + } + /** * Is password on public link requires * diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php index f65f7a4c56bfd..b1d703cd39956 100644 --- a/lib/public/Share/IManager.php +++ b/lib/public/Share/IManager.php @@ -295,11 +295,31 @@ public function newShare(); */ public function shareApiEnabled(); + /** + * Check if public link sharing is enabled globally + * + * @return bool + * @since 33.0.0 + */ + public function isLinkSharingEnabled(): bool; + + /** + * Check if a specific user can create public link shares + * + * This considers both global settings and user-specific group restrictions + * + * @param string|null $userId The user ID to check, or null for current user + * @return bool + * @since 33.0.0 + */ + public function canUserCreateLinkShares(?string $userId = null): bool; + /** * Is public link sharing enabled * * @return bool * @since 9.0.0 + * @deprecated 33.0.0 Use isLinkSharingEnabled() or canUserCreateLinkShares() instead */ public function shareApiAllowLinks();