diff --git a/apps/files_sharing/src/components/SharingInput.vue b/apps/files_sharing/src/components/SharingInput.vue index 6fb33aba6b2..2228f7d0c44 100644 --- a/apps/files_sharing/src/components/SharingInput.vue +++ b/apps/files_sharing/src/components/SharingInput.vue @@ -457,6 +457,20 @@ export default { } }, + /** + * Filter suggestion results based on trusted server configuration + * + * @param {object} result The raw suggestion result from API + * @return {boolean} Whether to include this result in suggestions + */ + filterByTrustedServer(result) { + const isRemoteEntity = result.value.shareType === ShareType.Remote || result.value.shareType === ShareType.RemoteGroup + if (isRemoteEntity && this.config.showFederatedSharesToTrustedServersAsInternal) { + return result.value.isTrustedServer === true + } + return true + }, + /** * Format shares for the multiselect options * diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php index 037c6f6cbea..828ec984148 100644 --- a/lib/private/Collaboration/Collaborators/RemotePlugin.php +++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php @@ -6,11 +6,13 @@ */ namespace OC\Collaboration\Collaborators; +use OCA\Federation\TrustedServers; use OCP\Collaboration\Collaborators\ISearchPlugin; use OCP\Collaboration\Collaborators\ISearchResult; use OCP\Collaboration\Collaborators\SearchResultType; use OCP\Contacts\IManager; use OCP\Federation\ICloudIdManager; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IUserManager; use OCP\IUserSession; @@ -27,11 +29,14 @@ class RemotePlugin implements ISearchPlugin { private IConfig $config, private IUserManager $userManager, IUserSession $userSession, + private IAppConfig $appConfig, + private TrustedServers $trustedServers, ) { $this->userId = $userSession->getUser()?->getUID() ?? ''; $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; } + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { $result = ['wide' => [], 'exact' => []]; $resultType = new SearchResultType('remotes'); @@ -67,9 +72,6 @@ class RemotePlugin implements ISearchPlugin { } $localUser = $this->userManager->get($remoteUser); - /** - * Add local share if remote cloud id matches a local user ones - */ if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) { $result['wide'][] = [ 'label' => $contact['FN'], @@ -95,6 +97,7 @@ class RemotePlugin implements ISearchPlugin { 'shareType' => IShare::TYPE_REMOTE, 'shareWith' => $cloudId, 'server' => $serverUrl, + 'isTrustedServer' => $this->trustedServers->isTrustedServer($serverUrl), ], ]; } else { @@ -107,6 +110,7 @@ class RemotePlugin implements ISearchPlugin { 'shareType' => IShare::TYPE_REMOTE, 'shareWith' => $cloudId, 'server' => $serverUrl, + 'isTrustedServer' => $this->trustedServers->isTrustedServer($serverUrl), ], ]; } @@ -120,9 +124,6 @@ class RemotePlugin implements ISearchPlugin { $result['wide'] = array_slice($result['wide'], $offset, $limit); } - /** - * Add generic share with remote item for valid cloud ids that are not users of the local instance - */ if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) { try { [$remoteUser, $serverUrl] = $this->splitUserRemote($search); @@ -136,6 +137,7 @@ class RemotePlugin implements ISearchPlugin { 'shareType' => IShare::TYPE_REMOTE, 'shareWith' => $search, 'server' => $serverUrl, + 'isTrustedServer' => $this->trustedServers->isTrustedServer($serverUrl), ], ]; } diff --git a/tests/lib/Collaboration/Collaborators/RemotePluginTest.php b/tests/lib/Collaboration/Collaborators/RemotePluginTest.php index a9a5e05dfe4..2d2f2743677 100644 --- a/tests/lib/Collaboration/Collaborators/RemotePluginTest.php +++ b/tests/lib/Collaboration/Collaborators/RemotePluginTest.php @@ -10,10 +10,12 @@ namespace Test\Collaboration\Collaborators; use OC\Collaboration\Collaborators\RemotePlugin; use OC\Collaboration\Collaborators\SearchResult; use OC\Federation\CloudIdManager; +use OCA\Federation\TrustedServers; use OCP\Collaboration\Collaborators\SearchResultType; use OCP\Contacts\IManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\Federation\ICloudIdManager; +use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IURLGenerator; @@ -21,6 +23,7 @@ use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class RemotePluginTest extends TestCase { @@ -36,6 +39,9 @@ class RemotePluginTest extends TestCase { /** @var ICloudIdManager|\PHPUnit\Framework\MockObject\MockObject */ protected $cloudIdManager; + protected IAppConfig|MockObject $appConfig; + protected ICloudIdManager|MockObject $trustedServers; + /** @var RemotePlugin */ protected $plugin; @@ -55,6 +61,8 @@ class RemotePluginTest extends TestCase { $this->createMock(IURLGenerator::class), $this->createMock(IUserManager::class), ); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->trustedServers = $this->createMock(TrustedServers::class); $this->searchResult = new SearchResult(); } @@ -67,7 +75,7 @@ class RemotePluginTest extends TestCase { $userSession->expects($this->any()) ->method('getUser') ->willReturn($user); - $this->plugin = new RemotePlugin($this->contactsManager, $this->cloudIdManager, $this->config, $this->userManager, $userSession); + $this->plugin = new RemotePlugin($this->contactsManager, $this->cloudIdManager, $this->config, $this->userManager, $userSession, $this->appConfig, $this->trustedServers); } /** @@ -141,6 +149,37 @@ class RemotePluginTest extends TestCase { $this->plugin->splitUserRemote($id); } + public function testTrustedServerMetadata(): void { + $this->config->expects($this->any()) + ->method('getAppValue') + ->willReturnCallback( + function ($appName, $key, $default) { + if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') { + return 'yes'; + } + return $default; + } + ); + + $this->trustedServers->expects($this->any()) + ->method('isTrustedServer') + ->willReturnCallback(function ($serverUrl) { + return $serverUrl === 'trustedserver.com'; + }); + + $this->instantiatePlugin(); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $this->plugin->search('test@trustedserver.com', 2, 0, $this->searchResult); + $result = $this->searchResult->asArray(); + + $this->assertNotEmpty($result['exact']['remotes']); + $this->assertTrue($result['exact']['remotes'][0]['value']['isTrustedServer']); + } + public static function dataGetRemote() { return [ ['test', [], true, ['remotes' => [], 'exact' => ['remotes' => []]], false, true], @@ -149,7 +188,7 @@ class RemotePluginTest extends TestCase { 'test@remote', [], true, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote'], 'uuid' => 'test', 'name' => 'test']]]], + ['remotes' => [], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote', 'isTrustedServer' => false], 'uuid' => 'test', 'name' => 'test']]]], false, true, ], @@ -157,7 +196,7 @@ class RemotePluginTest extends TestCase { 'test@remote', [], false, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote'], 'uuid' => 'test', 'name' => 'test']]]], + ['remotes' => [], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote', 'isTrustedServer' => false], 'uuid' => 'test', 'name' => 'test']]]], false, true, ], @@ -183,7 +222,7 @@ class RemotePluginTest extends TestCase { ], ], true, - ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => []]], + ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost', 'isTrustedServer' => false]]], 'exact' => ['remotes' => []]], false, true, ], @@ -235,7 +274,7 @@ class RemotePluginTest extends TestCase { ], ], true, - ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote'], 'uuid' => 'test', 'name' => 'test']]]], + ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost', 'isTrustedServer' => false]]], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote', 'isTrustedServer' => false], 'uuid' => 'test', 'name' => 'test']]]], false, true, ], @@ -261,7 +300,7 @@ class RemotePluginTest extends TestCase { ], ], false, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote'], 'uuid' => 'test', 'name' => 'test']]]], + ['remotes' => [], 'exact' => ['remotes' => [['label' => 'test (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'test@remote', 'server' => 'remote', 'isTrustedServer' => false], 'uuid' => 'test', 'name' => 'test']]]], false, true, ], @@ -287,7 +326,7 @@ class RemotePluginTest extends TestCase { ], ], true, - ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]], + ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost', 'isTrustedServer' => false]]]]], true, true, ], @@ -313,7 +352,7 @@ class RemotePluginTest extends TestCase { ], ], false, - ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]], + ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost', 'isTrustedServer' => false]]]]], true, true, ], @@ -340,7 +379,7 @@ class RemotePluginTest extends TestCase { ], ], false, - ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User Name @ Localhost', 'label' => 'User Name @ Localhost (user name@localhost)', 'uuid' => 'uid3', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost']]]]], + ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User Name @ Localhost', 'label' => 'User Name @ Localhost (user name@localhost)', 'uuid' => 'uid3', 'type' => '', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost', 'isTrustedServer' => false]]]]], true, true, ], @@ -367,7 +406,7 @@ class RemotePluginTest extends TestCase { ], ], false, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'user space (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'user space@remote', 'server' => 'remote'], 'uuid' => 'user space', 'name' => 'user space']]]], + ['remotes' => [], 'exact' => ['remotes' => [['label' => 'user space (remote)', 'value' => ['shareType' => IShare::TYPE_REMOTE, 'shareWith' => 'user space@remote', 'server' => 'remote', 'isTrustedServer' => false], 'uuid' => 'user space', 'name' => 'user space']]]], false, true, ],