aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files_sharing/lib/Controller/ShareAPIController.php7
-rw-r--r--apps/files_sharing/tests/ApiTest.php38
-rw-r--r--apps/files_sharing/tests/Controller/ShareAPIControllerTest.php12
-rw-r--r--apps/settings/lib/Settings/Admin/Sharing.php4
-rw-r--r--apps/settings/src/components/AdminSettingsSharingForm.vue5
-rw-r--r--apps/settings/tests/Settings/Admin/SharingTest.php15
-rw-r--r--build/integration/features/bootstrap/Sharing.php2
-rw-r--r--build/integration/features/bootstrap/SharingContext.php1
-rw-r--r--core/AppInfo/Application.php3
-rw-r--r--core/AppInfo/ConfigLexicon.php43
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
12 files changed, 120 insertions, 12 deletions
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php
index a19eb50faf7..7591493167f 100644
--- a/apps/files_sharing/lib/Controller/ShareAPIController.php
+++ b/apps/files_sharing/lib/Controller/ShareAPIController.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace OCA\Files_Sharing\Controller;
use Exception;
+use OC\Core\AppInfo\ConfigLexicon;
use OC\Files\FileInfo;
use OC\Files\Storage\Wrapper\Wrapper;
use OCA\Circles\Api\v1\Circles;
@@ -41,6 +42,7 @@ use OCP\Files\Mount\IShareOwnerlessMount;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\HintException;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IDateTimeZone;
use OCP\IGroupManager;
@@ -88,6 +90,7 @@ class ShareAPIController extends OCSController {
private IURLGenerator $urlGenerator,
private IL10N $l,
private IConfig $config,
+ private IAppConfig $appConfig,
private IAppManager $appManager,
private ContainerInterface $serverContainer,
private IUserStatusManager $userStatusManager,
@@ -969,9 +972,9 @@ class ShareAPIController extends OCSController {
: Constants::PERMISSION_READ;
}
- // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
if ($this->hasPermission($permissions, Constants::PERMISSION_READ)
- && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
+ && $this->shareManager->outgoingServer2ServerSharesAllowed()
+ && $this->appConfig->getValueBool('core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES)) {
$permissions |= Constants::PERMISSION_SHARE;
}
diff --git a/apps/files_sharing/tests/ApiTest.php b/apps/files_sharing/tests/ApiTest.php
index bb686c1ea8c..676809eebff 100644
--- a/apps/files_sharing/tests/ApiTest.php
+++ b/apps/files_sharing/tests/ApiTest.php
@@ -7,6 +7,7 @@
*/
namespace OCA\Files_Sharing\Tests;
+use OC\Core\AppInfo\ConfigLexicon;
use OC\Files\Cache\Scanner;
use OC\Files\FileInfo;
use OC\Files\Filesystem;
@@ -21,6 +22,7 @@ use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\Constants;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IDateTimeZone;
use OCP\IGroupManager;
@@ -35,6 +37,7 @@ use OCP\Server;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\UserStatus\IManager as IUserStatusManager;
+use PHPUnit\Framework\MockObject\MockObject;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
@@ -50,11 +53,9 @@ class ApiTest extends TestCase {
private static $tempStorage;
- /** @var Folder */
- private $userFolder;
-
- /** @var string */
- private $subsubfolder;
+ private Folder $userFolder;
+ private string $subsubfolder;
+ protected IAppConfig&MockObject $appConfig;
protected function setUp(): void {
parent::setUp();
@@ -81,6 +82,8 @@ class ApiTest extends TestCase {
$mount->getStorage()->getScanner()->scan('', Scanner::SCAN_RECURSIVE);
$this->userFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1);
+
+ $this->appConfig = $this->createMock(IAppConfig::class);
}
protected function tearDown(): void {
@@ -126,6 +129,7 @@ class ApiTest extends TestCase {
Server::get(IURLGenerator::class),
$l,
$config,
+ $this->appConfig,
$appManager,
$serverContainer,
$userStatusManager,
@@ -233,8 +237,12 @@ class ApiTest extends TestCase {
/**
* @group RoutingWeirdness
+ * @dataProvider dataAllowFederationOnPublicShares
*/
- public function testCreateShareLinkPublicUpload(): void {
+ public function testCreateShareLinkPublicUpload(array $appConfig, int $permissions): void {
+ $this->appConfig->method('getValueBool')
+ ->willReturnMap([$appConfig]);
+
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
$ocs->cleanup();
@@ -245,7 +253,7 @@ class ApiTest extends TestCase {
| Constants::PERMISSION_CREATE
| Constants::PERMISSION_UPDATE
| Constants::PERMISSION_DELETE
- | Constants::PERMISSION_SHARE,
+ | $permissions,
$data['permissions']
);
$this->assertEmpty($data['expiration']);
@@ -1005,8 +1013,13 @@ class ApiTest extends TestCase {
/**
* @medium
+ * @dataProvider dataAllowFederationOnPublicShares
*/
- public function testUpdateShareUpload(): void {
+ public function testUpdateShareUpload(array $appConfig, int $permissions): void {
+ $this->appConfig->method('getValueBool')->willReturnMap([
+ $appConfig,
+ ]);
+
$node1 = $this->userFolder->get($this->folder);
$share1 = $this->shareManager->newShare();
$share1->setNode($node1)
@@ -1026,7 +1039,7 @@ class ApiTest extends TestCase {
| Constants::PERMISSION_CREATE
| Constants::PERMISSION_UPDATE
| Constants::PERMISSION_DELETE
- | Constants::PERMISSION_SHARE,
+ | $permissions,
$share1->getPermissions()
);
@@ -1034,6 +1047,13 @@ class ApiTest extends TestCase {
$this->shareManager->deleteShare($share1);
}
+ public static function dataAllowFederationOnPublicShares(): array {
+ return [
+ [['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, false], 0],
+ [['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, true], Constants::PERMISSION_SHARE],
+ ];
+ }
+
/**
* @medium
*/
diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
index 8bb220d684b..abc405fc21c 100644
--- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
+++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
@@ -22,6 +22,7 @@ use OCP\Files\Mount\IMountPoint;
use OCP\Files\Mount\IShareOwnerlessMount;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IDateTimeZone;
use OCP\IGroup;
@@ -71,6 +72,7 @@ class ShareAPIControllerTest extends TestCase {
private IURLGenerator&MockObject $urlGenerator;
private IL10N&MockObject $l;
private IConfig&MockObject $config;
+ private IAppConfig&MockObject $appConfig;
private IAppManager&MockObject $appManager;
private ContainerInterface&MockObject $serverContainer;
private IUserStatusManager&MockObject $userStatusManager;
@@ -103,6 +105,7 @@ class ShareAPIControllerTest extends TestCase {
return vsprintf($text, $parameters);
});
$this->config = $this->createMock(IConfig::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->serverContainer = $this->createMock(ContainerInterface::class);
$this->userStatusManager = $this->createMock(IUserStatusManager::class);
@@ -127,6 +130,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -155,6 +159,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -838,6 +843,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -1469,6 +1475,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -1856,6 +1863,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -1954,6 +1962,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -2380,6 +2389,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -2451,6 +2461,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
@@ -2689,6 +2700,7 @@ class ShareAPIControllerTest extends TestCase {
$this->urlGenerator,
$this->l,
$this->config,
+ $this->appConfig,
$this->appManager,
$this->serverContainer,
$this->userStatusManager,
diff --git a/apps/settings/lib/Settings/Admin/Sharing.php b/apps/settings/lib/Settings/Admin/Sharing.php
index 3dede7fbdb4..e038b2a6231 100644
--- a/apps/settings/lib/Settings/Admin/Sharing.php
+++ b/apps/settings/lib/Settings/Admin/Sharing.php
@@ -6,10 +6,12 @@
*/
namespace OCA\Settings\Settings\Admin;
+use OC\Core\AppInfo\ConfigLexicon;
use OCP\App\IAppManager;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Constants;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
@@ -20,6 +22,7 @@ use OCP\Util;
class Sharing implements IDelegatedSettings {
public function __construct(
private IConfig $config,
+ private IAppConfig $appConfig,
private IL10N $l,
private IManager $shareManager,
private IAppManager $appManager,
@@ -47,6 +50,7 @@ class Sharing implements IDelegatedSettings {
'allowPublicUpload' => $this->getHumanBooleanConfig('core', 'shareapi_allow_public_upload', true),
'allowResharing' => $this->getHumanBooleanConfig('core', 'shareapi_allow_resharing', true),
'allowShareDialogUserEnumeration' => $this->getHumanBooleanConfig('core', 'shareapi_allow_share_dialog_user_enumeration', true),
+ 'allowFederationOnPublicShares' => $this->appConfig->getValueBool('core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES),
'restrictUserEnumerationToGroup' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_to_group'),
'restrictUserEnumerationToPhone' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_to_phone'),
'restrictUserEnumerationFullMatch' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match', true),
diff --git a/apps/settings/src/components/AdminSettingsSharingForm.vue b/apps/settings/src/components/AdminSettingsSharingForm.vue
index 1973781edee..c582e9febee 100644
--- a/apps/settings/src/components/AdminSettingsSharingForm.vue
+++ b/apps/settings/src/components/AdminSettingsSharingForm.vue
@@ -48,6 +48,10 @@
<NcCheckboxRadioSwitch :checked.sync="settings.allowPublicUpload">
{{ t('settings', 'Allow public uploads') }}
</NcCheckboxRadioSwitch>
+ <NcCheckboxRadioSwitch v-model="settings.allowFederationOnPublicShares">
+ {{ t('settings', 'Allow public shares to be added to other clouds by federation.') }}
+ {{ t('settings', 'This will add share permissions to all newly created link shares.') }}
+ </NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :checked.sync="settings.enableLinkPasswordByDefault">
{{ t('settings', 'Always ask for a password') }}
</NcCheckboxRadioSwitch>
@@ -241,6 +245,7 @@ interface IShareSettings {
allowPublicUpload: boolean
allowResharing: boolean
allowShareDialogUserEnumeration: boolean
+ allowFederationOnPublicShares: boolean
restrictUserEnumerationToGroup: boolean
restrictUserEnumerationToPhone: boolean
restrictUserEnumerationFullMatch: boolean
diff --git a/apps/settings/tests/Settings/Admin/SharingTest.php b/apps/settings/tests/Settings/Admin/SharingTest.php
index 62e3440fa54..12ab5c3cada 100644
--- a/apps/settings/tests/Settings/Admin/SharingTest.php
+++ b/apps/settings/tests/Settings/Admin/SharingTest.php
@@ -11,6 +11,7 @@ use OCP\App\IAppManager;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Constants;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
@@ -19,18 +20,22 @@ use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class SharingTest extends TestCase {
+ private Sharing $admin;
+
private IConfig&MockObject $config;
+ private IAppConfig&MockObject $appConfig;
private IL10N&MockObject $l10n;
private IManager&MockObject $shareManager;
private IAppManager&MockObject $appManager;
private IURLGenerator&MockObject $urlGenerator;
private IInitialState&MockObject $initialState;
- private Sharing $admin;
protected function setUp(): void {
parent::setUp();
$this->config = $this->createMock(IConfig::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
$this->l10n = $this->createMock(IL10N::class);
+
$this->shareManager = $this->createMock(IManager::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
@@ -38,6 +43,7 @@ class SharingTest extends TestCase {
$this->admin = new Sharing(
$this->config,
+ $this->appConfig,
$this->l10n,
$this->shareManager,
$this->appManager,
@@ -48,6 +54,12 @@ class SharingTest extends TestCase {
}
public function testGetFormWithoutExcludedGroups(): void {
+ $this->appConfig
+ ->method('getValueBool')
+ ->willReturnMap([
+ ['core', 'shareapi_allow_federation_on_public_shares', false, false, true],
+ ]);
+
$this->config
->method('getAppValue')
->willReturnMap([
@@ -103,6 +115,7 @@ class SharingTest extends TestCase {
'allowPublicUpload' => true,
'allowResharing' => true,
'allowShareDialogUserEnumeration' => true,
+ 'allowFederationOnPublicShares' => true,
'restrictUserEnumerationToGroup' => false,
'restrictUserEnumerationToPhone' => false,
'restrictUserEnumerationFullMatch' => true,
diff --git a/build/integration/features/bootstrap/Sharing.php b/build/integration/features/bootstrap/Sharing.php
index 039ee7d1121..0cc490ff110 100644
--- a/build/integration/features/bootstrap/Sharing.php
+++ b/build/integration/features/bootstrap/Sharing.php
@@ -337,6 +337,8 @@ trait Sharing {
return $this->isExpectedUrl((string)$data->$field, 'index.php/s/');
} elseif ($contentExpected == $data->$field) {
return true;
+ } else {
+ print($data->$field);
}
return false;
}
diff --git a/build/integration/features/bootstrap/SharingContext.php b/build/integration/features/bootstrap/SharingContext.php
index fe4d3bb6bf1..a9dd99108a9 100644
--- a/build/integration/features/bootstrap/SharingContext.php
+++ b/build/integration/features/bootstrap/SharingContext.php
@@ -29,6 +29,7 @@ class SharingContext implements Context, SnippetAcceptingContext {
$this->deleteServerConfig('core', 'shareapi_default_expire_date');
$this->deleteServerConfig('core', 'shareapi_expire_after_n_days');
$this->deleteServerConfig('core', 'link_defaultExpDays');
+ $this->deleteServerConfig('core', 'shareapi_allow_federation_on_public_shares');
$this->deleteServerConfig('files_sharing', 'outgoing_server2server_share_enabled');
$this->deleteServerConfig('core', 'shareapi_allow_view_without_download');
diff --git a/core/AppInfo/Application.php b/core/AppInfo/Application.php
index b94f010b02b..f1fe7d763e3 100644
--- a/core/AppInfo/Application.php
+++ b/core/AppInfo/Application.php
@@ -78,6 +78,9 @@ class Application extends App implements IBootstrap {
// Tags
$context->registerEventListener(UserDeletedEvent::class, TagManager::class);
+
+ // config lexicon
+ $context->registerConfigLexicon(ConfigLexicon::class);
}
public function boot(IBootContext $context): void {
diff --git a/core/AppInfo/ConfigLexicon.php b/core/AppInfo/ConfigLexicon.php
new file mode 100644
index 00000000000..cc7fd1a3b09
--- /dev/null
+++ b/core/AppInfo/ConfigLexicon.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Core\AppInfo;
+
+use NCU\Config\Lexicon\ConfigLexiconEntry;
+use NCU\Config\Lexicon\ConfigLexiconStrictness;
+use NCU\Config\Lexicon\IConfigLexicon;
+use NCU\Config\ValueType;
+
+/**
+ * Config Lexicon for core.
+ *
+ * Please Add & Manage your Config Keys in that file and keep the Lexicon up to date!
+ */
+class ConfigLexicon implements IConfigLexicon {
+ public const SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES = 'shareapi_allow_federation_on_public_shares';
+
+ public function getStrictness(): ConfigLexiconStrictness {
+ return ConfigLexiconStrictness::IGNORE;
+ }
+
+ public function getAppConfigs(): array {
+ return [
+ new ConfigLexiconEntry(
+ key: self::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES,
+ type: ValueType::BOOL,
+ lazy: true,
+ defaultRaw: true,
+ definition: 'adds share permission to public shares to allow adding them to your Nextcloud (federation)',
+ ),
+ ];
+ }
+
+ public function getUserConfigs(): array {
+ return [];
+ }
+}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index b3505bdd8e0..16926e77775 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -1224,6 +1224,7 @@ return array(
'OC\\Contacts\\ContactsMenu\\Providers\\ProfileProvider' => $baseDir . '/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php',
'OC\\ContextChat\\ContentManager' => $baseDir . '/lib/private/ContextChat/ContentManager.php',
'OC\\Core\\AppInfo\\Application' => $baseDir . '/core/AppInfo/Application.php',
+ 'OC\\Core\\AppInfo\\ConfigLexicon' => $baseDir . '/core/AppInfo/ConfigLexicon.php',
'OC\\Core\\BackgroundJobs\\BackgroundCleanupUpdaterBackupsJob' => $baseDir . '/core/BackgroundJobs/BackgroundCleanupUpdaterBackupsJob.php',
'OC\\Core\\BackgroundJobs\\CheckForUserCertificates' => $baseDir . '/core/BackgroundJobs/CheckForUserCertificates.php',
'OC\\Core\\BackgroundJobs\\CleanupLoginFlowV2' => $baseDir . '/core/BackgroundJobs/CleanupLoginFlowV2.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 15ae0a9373f..daa1a1940dd 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1265,6 +1265,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Contacts\\ContactsMenu\\Providers\\ProfileProvider' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php',
'OC\\ContextChat\\ContentManager' => __DIR__ . '/../../..' . '/lib/private/ContextChat/ContentManager.php',
'OC\\Core\\AppInfo\\Application' => __DIR__ . '/../../..' . '/core/AppInfo/Application.php',
+ 'OC\\Core\\AppInfo\\ConfigLexicon' => __DIR__ . '/../../..' . '/core/AppInfo/ConfigLexicon.php',
'OC\\Core\\BackgroundJobs\\BackgroundCleanupUpdaterBackupsJob' => __DIR__ . '/../../..' . '/core/BackgroundJobs/BackgroundCleanupUpdaterBackupsJob.php',
'OC\\Core\\BackgroundJobs\\CheckForUserCertificates' => __DIR__ . '/../../..' . '/core/BackgroundJobs/CheckForUserCertificates.php',
'OC\\Core\\BackgroundJobs\\CleanupLoginFlowV2' => __DIR__ . '/../../..' . '/core/BackgroundJobs/CleanupLoginFlowV2.php',