diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index 25f9c0eaf3f17..09cd5bf8c5e64 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -50,6 +50,7 @@ 'OCA\\Files\\Command\\ScanAppData' => $baseDir . '/../lib/Command/ScanAppData.php', 'OCA\\Files\\Command\\TransferOwnership' => $baseDir . '/../lib/Command/TransferOwnership.php', 'OCA\\Files\\Command\\WindowsCompatibleFilenames' => $baseDir . '/../lib/Command/WindowsCompatibleFilenames.php', + 'OCA\\Files\\ConfigLexicon' => $baseDir . '/../lib/ConfigLexicon.php', 'OCA\\Files\\Controller\\ApiController' => $baseDir . '/../lib/Controller/ApiController.php', 'OCA\\Files\\Controller\\ConversionApiController' => $baseDir . '/../lib/Controller/ConversionApiController.php', 'OCA\\Files\\Controller\\DirectEditingController' => $baseDir . '/../lib/Controller/DirectEditingController.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 75c5f40cd815c..5234caa67640c 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -65,6 +65,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\Command\\ScanAppData' => __DIR__ . '/..' . '/../lib/Command/ScanAppData.php', 'OCA\\Files\\Command\\TransferOwnership' => __DIR__ . '/..' . '/../lib/Command/TransferOwnership.php', 'OCA\\Files\\Command\\WindowsCompatibleFilenames' => __DIR__ . '/..' . '/../lib/Command/WindowsCompatibleFilenames.php', + 'OCA\\Files\\ConfigLexicon' => __DIR__ . '/..' . '/../lib/ConfigLexicon.php', 'OCA\\Files\\Controller\\ApiController' => __DIR__ . '/..' . '/../lib/Controller/ApiController.php', 'OCA\\Files\\Controller\\ConversionApiController' => __DIR__ . '/..' . '/../lib/Controller/ConversionApiController.php', 'OCA\\Files\\Controller\\DirectEditingController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingController.php', diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 1de8e60ab5a58..8ffdd3479c41a 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -13,6 +13,7 @@ use OCA\Files\Capabilities; use OCA\Files\Collaboration\Resources\Listener; use OCA\Files\Collaboration\Resources\ResourceProvider; +use OCA\Files\ConfigLexicon; use OCA\Files\Controller\ApiController; use OCA\Files\Dashboard\FavoriteWidget; use OCA\Files\DirectEditingCapabilities; @@ -124,6 +125,9 @@ public function register(IRegistrationContext $context): void { $context->registerNotifierService(Notifier::class); $context->registerDashboardWidget(FavoriteWidget::class); + + $context->registerConfigLexicon(ConfigLexicon::class); + } public function boot(IBootContext $context): void { diff --git a/apps/files/lib/ConfigLexicon.php b/apps/files/lib/ConfigLexicon.php new file mode 100644 index 0000000000000..a2df81cf78e53 --- /dev/null +++ b/apps/files/lib/ConfigLexicon.php @@ -0,0 +1,46 @@ + - 1.25.0 + 1.25.1 agpl Robin Appelman Michael Gapczynski diff --git a/apps/files_external/composer/composer/autoload_classmap.php b/apps/files_external/composer/composer/autoload_classmap.php index 8ac551013bdc4..61165ee67fbdc 100644 --- a/apps/files_external/composer/composer/autoload_classmap.php +++ b/apps/files_external/composer/composer/autoload_classmap.php @@ -107,6 +107,7 @@ 'OCA\\Files_External\\Migration\\Version1011Date20200630192246' => $baseDir . '/../lib/Migration/Version1011Date20200630192246.php', 'OCA\\Files_External\\Migration\\Version1015Date20211104103506' => $baseDir . '/../lib/Migration/Version1015Date20211104103506.php', 'OCA\\Files_External\\Migration\\Version1016Date20220324154536' => $baseDir . '/../lib/Migration/Version1016Date20220324154536.php', + 'OCA\\Files_External\\Migration\\Version1025Date20250228162604' => $baseDir . '/../lib/Migration/Version1025Date20250228162604.php', 'OCA\\Files_External\\Migration\\Version22000Date20210216084416' => $baseDir . '/../lib/Migration/Version22000Date20210216084416.php', 'OCA\\Files_External\\MountConfig' => $baseDir . '/../lib/MountConfig.php', 'OCA\\Files_External\\NotFoundException' => $baseDir . '/../lib/NotFoundException.php', diff --git a/apps/files_external/composer/composer/autoload_static.php b/apps/files_external/composer/composer/autoload_static.php index 4468ce1b6bb7f..5b8b6ab029479 100644 --- a/apps/files_external/composer/composer/autoload_static.php +++ b/apps/files_external/composer/composer/autoload_static.php @@ -122,6 +122,7 @@ class ComposerStaticInitFiles_External 'OCA\\Files_External\\Migration\\Version1011Date20200630192246' => __DIR__ . '/..' . '/../lib/Migration/Version1011Date20200630192246.php', 'OCA\\Files_External\\Migration\\Version1015Date20211104103506' => __DIR__ . '/..' . '/../lib/Migration/Version1015Date20211104103506.php', 'OCA\\Files_External\\Migration\\Version1016Date20220324154536' => __DIR__ . '/..' . '/../lib/Migration/Version1016Date20220324154536.php', + 'OCA\\Files_External\\Migration\\Version1025Date20250228162604' => __DIR__ . '/..' . '/../lib/Migration/Version1025Date20250228162604.php', 'OCA\\Files_External\\Migration\\Version22000Date20210216084416' => __DIR__ . '/..' . '/../lib/Migration/Version22000Date20210216084416.php', 'OCA\\Files_External\\MountConfig' => __DIR__ . '/..' . '/../lib/MountConfig.php', 'OCA\\Files_External\\NotFoundException' => __DIR__ . '/..' . '/../lib/NotFoundException.php', diff --git a/apps/files_external/lib/Migration/Version1025Date20250228162604.php b/apps/files_external/lib/Migration/Version1025Date20250228162604.php new file mode 100644 index 0000000000000..f3d76ed7baa4e --- /dev/null +++ b/apps/files_external/lib/Migration/Version1025Date20250228162604.php @@ -0,0 +1,35 @@ +globalStoragesServices->updateOverwriteHomeFolders(); + } +} diff --git a/apps/files_external/lib/Service/DBConfigService.php b/apps/files_external/lib/Service/DBConfigService.php index 5a8ee84ee47b5..984b9313e419d 100644 --- a/apps/files_external/lib/Service/DBConfigService.php +++ b/apps/files_external/lib/Service/DBConfigService.php @@ -5,6 +5,7 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OCA\Files_External\Service; use OCP\DB\Exception; @@ -64,16 +65,16 @@ public function getMountsForUser($userId, $groupIds) { ->where($builder->expr()->orX( $builder->expr()->andX( // global mounts $builder->expr()->eq('a.type', $builder->createNamedParameter(self::APPLICABLE_TYPE_GLOBAL, IQueryBuilder::PARAM_INT)), - $builder->expr()->isNull('a.value') + $builder->expr()->isNull('a.value'), ), $builder->expr()->andX( // mounts for user $builder->expr()->eq('a.type', $builder->createNamedParameter(self::APPLICABLE_TYPE_USER, IQueryBuilder::PARAM_INT)), - $builder->expr()->eq('a.value', $builder->createNamedParameter($userId)) + $builder->expr()->eq('a.value', $builder->createNamedParameter($userId)), ), $builder->expr()->andX( // mounts for group $builder->expr()->eq('a.type', $builder->createNamedParameter(self::APPLICABLE_TYPE_GROUP, IQueryBuilder::PARAM_INT)), - $builder->expr()->in('a.value', $builder->createNamedParameter($groupIds, IQueryBuilder::PARAM_STR_ARRAY)) - ) + $builder->expr()->in('a.value', $builder->createNamedParameter($groupIds, IQueryBuilder::PARAM_STR_ARRAY)), + ), )); return $this->getMountsFromQuery($query); @@ -94,8 +95,8 @@ protected function modifyMountsOnDelete(string $applicableId, int $applicableTyp ->leftJoin('a', 'external_applicable', 'b', $builder->expr()->eq('a.mount_id', 'b.mount_id')) ->where($builder->expr()->andX( $builder->expr()->eq('b.type', $builder->createNamedParameter($applicableType, IQueryBuilder::PARAM_INT)), - $builder->expr()->eq('b.value', $builder->createNamedParameter($applicableId)) - ) + $builder->expr()->eq('b.value', $builder->createNamedParameter($applicableId)), + ), ) ->groupBy(['a.mount_id']); $stmt = $query->executeQuery(); @@ -227,7 +228,7 @@ public function addMount($mountPoint, $storageBackend, $authBackend, $priority, 'storage_backend' => $builder->createNamedParameter($storageBackend, IQueryBuilder::PARAM_STR), 'auth_backend' => $builder->createNamedParameter($authBackend, IQueryBuilder::PARAM_STR), 'priority' => $builder->createNamedParameter($priority, IQueryBuilder::PARAM_INT), - 'type' => $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT) + 'type' => $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT), ]); $query->executeStatement(); return $query->getLastInsertId(); @@ -507,4 +508,17 @@ private function decryptValue($value) { return $value; } } + + /** + * Check if any mountpoint is configured that overwrite the home folder + */ + public function hasHomeFolderOverwriteMount(): bool { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->select('mount_id') + ->from('external_mounts') + ->where($builder->expr()->eq('mount_point', $builder->createNamedParameter('/'))) + ->setMaxResults(1); + $result = $query->executeQuery(); + return count($result->fetchAll()) > 0; + } } diff --git a/apps/files_external/lib/Service/StoragesService.php b/apps/files_external/lib/Service/StoragesService.php index a12a8fc245a60..7b1b7ba2dc1ff 100644 --- a/apps/files_external/lib/Service/StoragesService.php +++ b/apps/files_external/lib/Service/StoragesService.php @@ -9,6 +9,9 @@ use OC\Files\Cache\Storage; use OC\Files\Filesystem; +use OCA\Files\AppInfo\Application as FilesApplication; +use OCA\Files\ConfigLexicon; +use OCA\Files_External\AppInfo\Application; use OCA\Files_External\Lib\Auth\AuthMechanism; use OCA\Files_External\Lib\Auth\InvalidAuth; use OCA\Files_External\Lib\Backend\Backend; @@ -20,6 +23,7 @@ use OCP\Files\Config\IUserMountCache; use OCP\Files\Events\InvalidateMountCacheEvent; use OCP\Files\StorageNotAvailableException; +use OCP\IAppConfig; use OCP\Server; use OCP\Util; use Psr\Log\LoggerInterface; @@ -40,6 +44,7 @@ public function __construct( protected DBConfigService $dbConfig, protected IUserMountCache $userMountCache, protected IEventDispatcher $eventDispatcher, + protected IAppConfig $appConfig, ) { } @@ -242,6 +247,9 @@ public function addStorage(StorageConfig $newStorage) { $this->triggerHooks($newStorage, Filesystem::signal_create_mount); $newStorage->setStatus(StorageNotAvailableException::STATUS_SUCCESS); + + $this->updateOverwriteHomeFolders(); + return $newStorage; } @@ -425,6 +433,8 @@ public function updateStorage(StorageConfig $updatedStorage) { } } + $this->updateOverwriteHomeFolders(); + return $this->getStorage($id); } @@ -449,6 +459,8 @@ public function removeStorage(int $id) { // delete oc_storages entries and oc_filecache Storage::cleanByMountId($id); + + $this->updateOverwriteHomeFolders(); } /** @@ -473,4 +485,20 @@ private function getStorageId(StorageConfig $storageConfig) { return -1; } } + + public function updateOverwriteHomeFolders(): void { + $appIdsList = $this->appConfig->getValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS); + + if ($this->dbConfig->hasHomeFolderOverwriteMount()) { + if (!in_array(Application::APP_ID, $appIdsList)) { + $appIdsList[] = Application::APP_ID; + $this->appConfig->setValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS, $appIdsList); + } + } else { + if (in_array(Application::APP_ID, $appIdsList)) { + $appIdsList = array_values(array_filter($appIdsList, fn ($v) => $v !== Application::APP_ID)); + $this->appConfig->setValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS, $appIdsList); + } + } + } } diff --git a/apps/files_external/lib/Service/UserGlobalStoragesService.php b/apps/files_external/lib/Service/UserGlobalStoragesService.php index aaa59c85d622d..6c943247b2069 100644 --- a/apps/files_external/lib/Service/UserGlobalStoragesService.php +++ b/apps/files_external/lib/Service/UserGlobalStoragesService.php @@ -10,6 +10,7 @@ use OCA\Files_External\Lib\StorageConfig; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; +use OCP\IAppConfig; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserSession; @@ -21,14 +22,6 @@ class UserGlobalStoragesService extends GlobalStoragesService { use UserTrait; - /** - * @param BackendService $backendService - * @param DBConfigService $dbConfig - * @param IUserSession $userSession - * @param IGroupManager $groupManager - * @param IUserMountCache $userMountCache - * @param IEventDispatcher $eventDispatcher - */ public function __construct( BackendService $backendService, DBConfigService $dbConfig, @@ -36,8 +29,9 @@ public function __construct( protected IGroupManager $groupManager, IUserMountCache $userMountCache, IEventDispatcher $eventDispatcher, + IAppConfig $appConfig, ) { - parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher); + parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher, $appConfig); $this->userSession = $userSession; } diff --git a/apps/files_external/lib/Service/UserStoragesService.php b/apps/files_external/lib/Service/UserStoragesService.php index 9d4192734b629..bd8dd2d348c1e 100644 --- a/apps/files_external/lib/Service/UserStoragesService.php +++ b/apps/files_external/lib/Service/UserStoragesService.php @@ -13,6 +13,7 @@ use OCA\Files_External\NotFoundException; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; +use OCP\IAppConfig; use OCP\IUserSession; /** @@ -24,12 +25,6 @@ class UserStoragesService extends StoragesService { /** * Create a user storages service - * - * @param BackendService $backendService - * @param DBConfigService $dbConfig - * @param IUserSession $userSession user session - * @param IUserMountCache $userMountCache - * @param IEventDispatcher $eventDispatcher */ public function __construct( BackendService $backendService, @@ -37,9 +32,10 @@ public function __construct( IUserSession $userSession, IUserMountCache $userMountCache, IEventDispatcher $eventDispatcher, + IAppConfig $appConfig, ) { $this->userSession = $userSession; - parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher); + parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher, $appConfig); } protected function readDBConfig() { diff --git a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php index 0a3749981c8b1..b4c8617830b1f 100644 --- a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php @@ -19,7 +19,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTestCase { protected function setUp(): void { parent::setUp(); - $this->service = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher); + $this->service = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher, $this->appConfig); } protected function tearDown(): void { diff --git a/apps/files_external/tests/Service/StoragesServiceTestCase.php b/apps/files_external/tests/Service/StoragesServiceTestCase.php index b41eb409468d3..991921880e88c 100644 --- a/apps/files_external/tests/Service/StoragesServiceTestCase.php +++ b/apps/files_external/tests/Service/StoragesServiceTestCase.php @@ -28,6 +28,7 @@ use OCP\Files\Config\IUserMountCache; use OCP\Files\Mount\IMountPoint; use OCP\Files\Storage\IStorage; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUser; @@ -57,12 +58,13 @@ public function clean() { */ abstract class StoragesServiceTestCase extends \Test\TestCase { protected StoragesService $service; - protected BackendService $backendService; + protected BackendService&MockObject $backendService; protected string $dataDir; protected CleaningDBConfig $dbConfig; protected static array $hookCalls; protected IUserMountCache&MockObject $mountCache; protected IEventDispatcher&MockObject $eventDispatcher; + protected IAppConfig&MockObject $appConfig; protected function setUp(): void { parent::setUp(); @@ -77,6 +79,7 @@ protected function setUp(): void { $this->mountCache = $this->createMock(IUserMountCache::class); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->appConfig = $this->createMock(IAppConfig::class); // prepare BackendService mock $this->backendService = $this->createMock(BackendService::class); diff --git a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php index 2a2f4596fda05..2119872ea5b8b 100644 --- a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php @@ -75,6 +75,7 @@ protected function setUp(): void { $this->groupManager, $this->mountCache, $this->eventDispatcher, + $this->appConfig, ); } diff --git a/apps/files_external/tests/Service/UserStoragesServiceTest.php b/apps/files_external/tests/Service/UserStoragesServiceTest.php index 0a2f291f6e459..8c7c4d1f2db3b 100644 --- a/apps/files_external/tests/Service/UserStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserStoragesServiceTest.php @@ -36,7 +36,7 @@ class UserStoragesServiceTest extends StoragesServiceTestCase { protected function setUp(): void { parent::setUp(); - $this->globalStoragesService = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher); + $this->globalStoragesService = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher, $this->appConfig); $this->userId = $this->getUniqueID('user_'); $this->createUser($this->userId, $this->userId); @@ -49,7 +49,7 @@ protected function setUp(): void { ->method('getUser') ->willReturn($this->user); - $this->service = new UserStoragesService($this->backendService, $this->dbConfig, $userSession, $this->mountCache, $this->eventDispatcher); + $this->service = new UserStoragesService($this->backendService, $this->dbConfig, $userSession, $this->mountCache, $this->eventDispatcher, $this->appConfig); } private function makeTestStorageData() { diff --git a/cypress/e2e/files_external/StorageUtils.ts b/cypress/e2e/files_external/StorageUtils.ts index 0f7fec65edfb7..33402feac1f43 100644 --- a/cypress/e2e/files_external/StorageUtils.ts +++ b/cypress/e2e/files_external/StorageUtils.ts @@ -9,10 +9,15 @@ export type StorageConfig = { [key: string]: string } +export type StorageMountOption = { + readonly: boolean +} + export enum StorageBackend { DAV = 'dav', SMB = 'smb', SFTP = 'sftp', + LOCAL = 'local', } export enum AuthBackend { @@ -22,6 +27,7 @@ export enum AuthBackend { SessionCredentials = 'password::sessioncredentials', UserGlobalAuth = 'password::global::user', UserProvided = 'password::userprovided', + Null = 'null::null', } /** @@ -35,4 +41,20 @@ export function createStorageWithConfig(mountPoint: string, storageBackend: Stor cy.log(`Creating storage with command: ${command}`) return cy.runOccCommand(command) + .then(({ stdout }) => { + return stdout.replace('Storage created with id ', '') + }) +} + +export function setStorageMountOptions(mountId: string, options: StorageMountOption) { + for (const [key, value] of Object.entries(options)) { + cy.runOccCommand(`files_external:option ${mountId} ${key} ${value}`) + } +} + +export function deleteAllExternalStorages() { + cy.runOccCommand('files_external:list --all --output=json').then(({ stdout }) => { + const list = JSON.parse(stdout) + list.forEach((storage) => cy.runOccCommand(`files_external:delete --yes ${storage.mount_id}`), { failOnNonZeroExit: false }) + }) } diff --git a/cypress/e2e/files_external/home-folder-root-mount-permissions.cy.ts b/cypress/e2e/files_external/home-folder-root-mount-permissions.cy.ts new file mode 100644 index 0000000000000..b2938e3106bc0 --- /dev/null +++ b/cypress/e2e/files_external/home-folder-root-mount-permissions.cy.ts @@ -0,0 +1,46 @@ +/** + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { User } from '@nextcloud/cypress' +import { AuthBackend, createStorageWithConfig, deleteAllExternalStorages, setStorageMountOptions, StorageBackend } from './StorageUtils' + +describe('Home folder root mount permissions', { testIsolation: true }, () => { + let user1: User + + before(() => { + cy.runOccCommand('app:enable files_external') + cy.createRandomUser().then((user) => { user1 = user }) + }) + + after(() => { + deleteAllExternalStorages() + cy.runOccCommand('app:disable files_external') + }) + + it('Does not show write actions on read-only storage mounted at the root of the user\'s home folder', () => { + cy.login(user1) + cy.visit('/apps/files/') + cy.runOccCommand('config:app:get files overwrites_home_folders --default-value=[]') + .then(({ stdout }) => assert.equal(stdout.trim(), '[]')) + + cy.get('[data-cy-upload-picker=""]').should('exist') + + createStorageWithConfig('/', StorageBackend.LOCAL, AuthBackend.Null, { datadir: '/tmp' }) + .then((id) => setStorageMountOptions(id, { readonly: true })) + // HACK: somehow, we need to create an external folder targeting a subpath for the previous one to show. + createStorageWithConfig('/a', StorageBackend.LOCAL, AuthBackend.Null, { datadir: '/tmp' }) + cy.visit('/apps/files/') + cy.visit('/apps/files/') + cy.runOccCommand('config:app:get files overwrites_home_folders') + .then(({ stdout }) => assert.equal(stdout.trim(), '["files_external"]')) + cy.get('[data-cy-upload-picker=""]').should('not.exist') + + deleteAllExternalStorages() + cy.visit('/apps/files/') + cy.runOccCommand('config:app:get files overwrites_home_folders') + .then(({ stdout }) => assert.equal(stdout.trim(), '[]')) + cy.get('[data-cy-upload-picker=""]').should('exist') + }) +}) diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php index 77479c2fa5e06..d7afb199b913f 100644 --- a/lib/private/Files/Node/LazyUserFolder.php +++ b/lib/private/Files/Node/LazyUserFolder.php @@ -19,38 +19,50 @@ use Psr\Log\LoggerInterface; class LazyUserFolder extends LazyFolder { - private IUser $user; private string $path; - private IMountManager $mountManager; - public function __construct(IRootFolder $rootFolder, IUser $user, IMountManager $mountManager) { - $this->user = $user; - $this->mountManager = $mountManager; + public function __construct( + IRootFolder $rootFolder, + private IUser $user, + private IMountManager $mountManager, + bool $useDefaultHomeFoldersPermissions = true, + ) { $this->path = '/' . $user->getUID() . '/files'; - parent::__construct($rootFolder, function () use ($user): Folder { - try { - $node = $this->getRootFolder()->get($this->path); - if ($node instanceof File) { - $e = new \RuntimeException(); - \OCP\Server::get(LoggerInterface::class)->error('User root storage is not a folder: ' . $this->path, [ - 'exception' => $e, - ]); - throw $e; - } - return $node; - } catch (NotFoundException $e) { - if (!$this->getRootFolder()->nodeExists('/' . $user->getUID())) { - $this->getRootFolder()->newFolder('/' . $user->getUID()); - } - return $this->getRootFolder()->newFolder($this->path); - } - }, [ + $data = [ 'path' => $this->path, - // Sharing user root folder is not allowed - 'permissions' => Constants::PERMISSION_ALL ^ Constants::PERMISSION_SHARE, 'type' => FileInfo::TYPE_FOLDER, 'mimetype' => FileInfo::MIMETYPE_FOLDER, - ]); + ]; + + // By default, we assume the permissions for the users' home folders. + // If a mount point is mounted on a user's home folder, the permissions cannot be assumed. + if ($useDefaultHomeFoldersPermissions) { + // Sharing user root folder is not allowed + $data['permissions'] = Constants::PERMISSION_ALL ^ Constants::PERMISSION_SHARE; + } + + parent::__construct( + $rootFolder, + function () use ($user): Folder { + try { + $node = $this->getRootFolder()->get($this->path); + if ($node instanceof File) { + $e = new \RuntimeException(); + \OCP\Server::get(LoggerInterface::class)->error('User root storage is not a folder: ' . $this->path, [ + 'exception' => $e, + ]); + throw $e; + } + return $node; + } catch (NotFoundException $e) { + if (!$this->getRootFolder()->nodeExists('/' . $user->getUID())) { + $this->getRootFolder()->newFolder('/' . $user->getUID()); + } + return $this->getRootFolder()->newFolder($this->path); + } + }, + $data, + ); } public function getMountPoint() { diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 76afca9dee806..9b0a48fa296fd 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -14,6 +14,8 @@ use OC\Files\View; use OC\Hooks\PublicEmitter; use OC\User\NoUserException; +use OCA\Files\AppInfo\Application; +use OCA\Files\ConfigLexicon; use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Cache\ICacheEntry; @@ -24,6 +26,7 @@ use OCP\Files\Node as INode; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\IAppConfig; use OCP\ICache; use OCP\ICacheFactory; use OCP\IUser; @@ -51,43 +54,30 @@ * @package OC\Files\Node */ class Root extends Folder implements IRootFolder { - private Manager $mountManager; private PublicEmitter $emitter; - private ?IUser $user; private CappedMemoryCache $userFolderCache; - private IUserMountCache $userMountCache; - private LoggerInterface $logger; - private IUserManager $userManager; - private IEventDispatcher $eventDispatcher; private ICache $pathByIdCache; + private bool $useDefaultHomeFoldersPermissions = true; - /** - * @param Manager $manager - * @param View $view - * @param IUser|null $user - */ public function __construct( - $manager, - $view, - $user, - IUserMountCache $userMountCache, - LoggerInterface $logger, - IUserManager $userManager, + private Manager $mountManager, + View $view, + private ?IUser $user, + private IUserMountCache $userMountCache, + private LoggerInterface $logger, + private IUserManager $userManager, IEventDispatcher $eventDispatcher, ICacheFactory $cacheFactory, + IAppConfig $appConfig, ) { parent::__construct($this, $view, ''); - $this->mountManager = $manager; - $this->user = $user; $this->emitter = new PublicEmitter(); $this->userFolderCache = new CappedMemoryCache(); - $this->userMountCache = $userMountCache; - $this->logger = $logger; - $this->userManager = $userManager; $eventDispatcher->addListener(FilesystemTornDownEvent::class, function () { $this->userFolderCache = new CappedMemoryCache(); }); $this->pathByIdCache = $cacheFactory->createLocal('path-by-id'); + $this->useDefaultHomeFoldersPermissions = count($appConfig->getValueArray(Application::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS)) === 0; } /** @@ -367,7 +357,7 @@ public function getUserFolder($userId) { $folder = $this->newFolder('/' . $userId . '/files'); } } else { - $folder = new LazyUserFolder($this, $userObject, $this->mountManager); + $folder = new LazyUserFolder($this, $userObject, $this->mountManager, $this->useDefaultHomeFoldersPermissions); } $this->userFolderCache->set($userId, $folder); diff --git a/lib/private/Server.php b/lib/private/Server.php index 5aacfb81ef9ea..c7910debcd8ae 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -402,6 +402,7 @@ public function __construct($webRoot, \OC\Config $config) { $this->get(IUserManager::class), $this->get(IEventDispatcher::class), $this->get(ICacheFactory::class), + $this->get(IAppConfig::class), ); $previewConnector = new \OC\Preview\WatcherConnector( diff --git a/tests/lib/Files/Node/FileTest.php b/tests/lib/Files/Node/FileTest.php index eec34d156ad9d..0ab8a32b6cbd0 100644 --- a/tests/lib/Files/Node/FileTest.php +++ b/tests/lib/Files/Node/FileTest.php @@ -44,7 +44,7 @@ protected function getViewDeleteMethod() { public function testGetContent(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $hook = function ($file): void { @@ -74,7 +74,7 @@ public function testGetContentNotPermitted(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) @@ -93,7 +93,7 @@ public function testGetContentNotPermitted(): void { public function testPutContent(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) @@ -120,7 +120,7 @@ public function testPutContentNotPermitted(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $this->view->expects($this->once()) @@ -135,7 +135,7 @@ public function testPutContentNotPermitted(): void { public function testGetMimeType(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $this->view->expects($this->once()) @@ -161,6 +161,7 @@ public function testFOpenRead(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $hook = function ($file): void { @@ -198,6 +199,7 @@ public function testFOpenWrite(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $hooksCalled = 0; $hook = function ($file) use (&$hooksCalled): void { @@ -239,6 +241,7 @@ public function testFOpenReadNotPermitted(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $hook = function ($file): void { throw new \Exception('Hooks are not supposed to be called'); @@ -266,6 +269,7 @@ public function testFOpenReadWriteNoReadPermissions(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $hook = function (): void { throw new \Exception('Hooks are not supposed to be called'); @@ -293,6 +297,7 @@ public function testFOpenReadWriteNoWritePermissions(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $hook = function (): void { throw new \Exception('Hooks are not supposed to be called'); diff --git a/tests/lib/Files/Node/FolderTest.php b/tests/lib/Files/Node/FolderTest.php index 439535cf2c110..fc8b778cb3474 100644 --- a/tests/lib/Files/Node/FolderTest.php +++ b/tests/lib/Files/Node/FolderTest.php @@ -76,7 +76,7 @@ public function testGetDirectoryContent(): void { * @var View|\PHPUnit\Framework\MockObject\MockObject $view */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -109,7 +109,7 @@ public function testGet(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -128,7 +128,7 @@ public function testNodeExists(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -148,7 +148,7 @@ public function testNodeExistsNotExists(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -166,7 +166,7 @@ public function testNewFolder(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -190,7 +190,7 @@ public function testNewFolderDeepParent(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -217,7 +217,7 @@ public function testNewFolderNotPermitted(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->method('getUser') ->willReturn($this->user); @@ -234,7 +234,7 @@ public function testNewFile(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -261,7 +261,7 @@ public function testNewFileNotPermitted(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->method('getUser') ->willReturn($this->user); @@ -278,7 +278,7 @@ public function testGetFreeSpace(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->method('getUser') ->willReturn($this->user); @@ -295,7 +295,7 @@ public function testSearch(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->method('getUser') ->willReturn($this->user); @@ -344,7 +344,7 @@ public function testSearchInRoot(): void { $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getUser', 'getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -387,7 +387,7 @@ public function testSearchInStorageRoot(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->method('getUser') ->willReturn($this->user); @@ -430,7 +430,7 @@ public function testSearchSubStorages(): void { $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') @@ -506,7 +506,7 @@ public function testGetById(): void { $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $storage = $this->createMock(Storage::class); $mount = new MountPoint($storage, '/bar'); @@ -555,7 +555,7 @@ public function testGetByIdMountRoot(): void { $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $storage = $this->createMock(Storage::class); $mount = new MountPoint($storage, '/bar'); @@ -600,7 +600,7 @@ public function testGetByIdOutsideFolder(): void { $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $storage = $this->createMock(Storage::class); $mount = new MountPoint($storage, '/bar'); @@ -644,7 +644,7 @@ public function testGetByIdMultipleStorages(): void { $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $storage = $this->createMock(Storage::class); $mount1 = new MountPoint($storage, '/bar'); @@ -703,7 +703,7 @@ public function testGetUniqueName($name, $existingFiles, $expected): void { $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getUser', 'getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $view->expects($this->any()) @@ -728,7 +728,7 @@ public function testRecent(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */ $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getUser', 'getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); /** @var \PHPUnit\Framework\MockObject\MockObject|FileInfo $folderInfo */ $folderInfo = $this->getMockBuilder(FileInfo::class) @@ -797,7 +797,7 @@ public function testRecentFolder(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */ $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getUser', 'getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); /** @var \PHPUnit\Framework\MockObject\MockObject|FileInfo $folderInfo */ $folderInfo = $this->getMockBuilder(FileInfo::class) @@ -864,7 +864,7 @@ public function testRecentJail(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */ $root = $this->getMockBuilder(Root::class) ->onlyMethods(['getUser', 'getMountsIn', 'getMount']) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); /** @var \PHPUnit\Framework\MockObject\MockObject|FileInfo $folderInfo */ $folderInfo = $this->getMockBuilder(FileInfo::class) @@ -951,7 +951,7 @@ public function testSearchSubStoragesLimitOffset(int $offset, int $limit, array $manager = $this->createMock(Manager::class); $view = $this->getRootViewMock(); $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); $root->expects($this->any()) ->method('getUser') diff --git a/tests/lib/Files/Node/HookConnectorTest.php b/tests/lib/Files/Node/HookConnectorTest.php index 3f3957bab1d3e..f108b27917986 100644 --- a/tests/lib/Files/Node/HookConnectorTest.php +++ b/tests/lib/Files/Node/HookConnectorTest.php @@ -32,6 +32,7 @@ use OCP\Files\Events\Node\NodeTouchedEvent; use OCP\Files\Events\Node\NodeWrittenEvent; use OCP\Files\Node; +use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IUserManager; use OCP\Server; @@ -88,6 +89,7 @@ protected function setUp(): void { $this->createMock(IUserManager::class), $this->createMock(IEventDispatcher::class), $cacheFactory, + $this->createMock(IAppConfig::class), ); $this->eventDispatcher = Server::get(IEventDispatcher::class); $this->logger = Server::get(LoggerInterface::class); diff --git a/tests/lib/Files/Node/IntegrationTest.php b/tests/lib/Files/Node/IntegrationTest.php index f059afa16250e..d7a56a0f99dd0 100644 --- a/tests/lib/Files/Node/IntegrationTest.php +++ b/tests/lib/Files/Node/IntegrationTest.php @@ -16,6 +16,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; use OCP\Files\Mount\IMountManager; +use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IUserManager; use OCP\Server; @@ -72,6 +73,7 @@ protected function setUp(): void { $this->createMock(IUserManager::class), $this->createMock(IEventDispatcher::class), $cacheFactory, + $this->createMock(IAppConfig::class), ); $storage = new Temporary([]); $subStorage = new Temporary([]); diff --git a/tests/lib/Files/Node/NodeTestCase.php b/tests/lib/Files/Node/NodeTestCase.php index 4aecd0fef11fc..90f7c2c0f65b3 100644 --- a/tests/lib/Files/Node/NodeTestCase.php +++ b/tests/lib/Files/Node/NodeTestCase.php @@ -16,7 +16,6 @@ use OC\Files\Storage\Storage; use OC\Files\View; use OC\Memcache\ArrayCache; -use OC\User\User; use OCP\Constants; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; @@ -27,9 +26,11 @@ use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\Files\Storage\IStorage; +use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IUser; use OCP\IUserManager; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; /** @@ -38,24 +39,16 @@ * @package Test\Files\Node */ abstract class NodeTestCase extends \Test\TestCase { - /** @var User */ - protected $user; - /** @var \OC\Files\Mount\Manager */ - protected $manager; - /** @var View|\PHPUnit\Framework\MockObject\MockObject */ - protected $view; - /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject */ - protected $root; - /** @var IUserMountCache|\PHPUnit\Framework\MockObject\MockObject */ - protected $userMountCache; - /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ - protected $logger; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $userManager; - /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ - protected $eventDispatcher; - /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $cacheFactory; + protected IUser&MockObject $user; + protected Manager&MockObject $manager; + protected View&MockObject $view; + protected Root&MockObject $root; + protected IUserMountCache&MockObject $userMountCache; + protected LoggerInterface&MockObject $logger; + protected IUserManager&MockObject $userManager; + protected IEventDispatcher&MockObject $eventDispatcher; + protected ICacheFactory&MockObject $cacheFactory; + protected IAppConfig&MockObject $appConfig; protected function setUp(): void { parent::setUp(); @@ -81,8 +74,10 @@ protected function setUp(): void { ->willReturnCallback(function () { return new ArrayCache(); }); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->getMock(); } @@ -194,6 +189,7 @@ public function testDeleteHooks(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->createMock(IAppConfig::class), ); $root->listen('\OC\Files', 'preDelete', $preListener); @@ -443,6 +439,7 @@ public function testTouchHooks(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->createMock(IAppConfig::class), ); $root->listen('\OC\Files', 'preTouch', $preListener); $root->listen('\OC\Files', 'postTouch', $postListener); @@ -619,7 +616,7 @@ public static function moveOrCopyProvider(): array { public function testMoveCopyHooks($operationMethod, $viewMethod, $preHookName, $postHookName): void { /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject $root */ $root = $this->getMockBuilder(Root::class) - ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) + ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig]) ->onlyMethods(['get']) ->getMock(); diff --git a/tests/lib/Files/Node/RootTest.php b/tests/lib/Files/Node/RootTest.php index d90e6a2cc6e0f..3821b6943b15b 100644 --- a/tests/lib/Files/Node/RootTest.php +++ b/tests/lib/Files/Node/RootTest.php @@ -16,15 +16,16 @@ use OC\Files\View; use OC\Memcache\ArrayCache; use OC\User\NoUserException; -use OC\User\User; use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IUser; use OCP\IUserManager; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; /** @@ -33,20 +34,14 @@ * @package Test\Files\Node */ class RootTest extends \Test\TestCase { - /** @var User */ - private $user; - /** @var \OC\Files\Mount\Manager */ - private $manager; - /** @var IUserMountCache|\PHPUnit\Framework\MockObject\MockObject */ - private $userMountCache; - /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ - private $logger; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - private $userManager; - /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ - private $eventDispatcher; - /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $cacheFactory; + private IUser&MockObject $user; + private Manager&MockObject $manager; + private IUserMountCache&MockObject $userMountCache; + private LoggerInterface&MockObject $logger; + private IUserManager&MockObject $userManager; + private IEventDispatcher&MockObject $eventDispatcher; + protected ICacheFactory&MockObject $cacheFactory; + protected IAppConfig&MockObject $appConfig; protected function setUp(): void { parent::setUp(); @@ -66,10 +61,11 @@ protected function setUp(): void { ->willReturnCallback(function () { return new ArrayCache(); }); + $this->appConfig = $this->createMock(IAppConfig::class); } /** - * @return View|\PHPUnit\Framework\MockObject\MockObject $view + * @return View&MockObject $view */ protected function getRootViewMock() { $view = $this->createMock(View::class); @@ -100,6 +96,7 @@ public function testGet(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $view->expects($this->once()) @@ -133,6 +130,7 @@ public function testGetNotFound(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $view->expects($this->once()) @@ -158,6 +156,7 @@ public function testGetInvalidPath(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $root->get('/../foo'); @@ -177,6 +176,7 @@ public function testGetNoStorages(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $root->get('/bar/foo'); @@ -192,6 +192,7 @@ public function testGetUserFolder(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $user = $this->createMock(IUser::class); $user @@ -203,7 +204,7 @@ public function testGetUserFolder(): void { ->method('get') ->with('MyUserId') ->willReturn($user); - /** @var CappedMemoryCache|\PHPUnit\Framework\MockObject\MockObject $cappedMemoryCache */ + /** @var CappedMemoryCache&MockObject $cappedMemoryCache */ $cappedMemoryCache = $this->createMock(CappedMemoryCache::class); $cappedMemoryCache ->expects($this->once()) @@ -234,6 +235,7 @@ public function testGetUserFolderWithNoUserObj(): void { $this->userManager, $this->eventDispatcher, $this->cacheFactory, + $this->appConfig, ); $this->userManager ->expects($this->once())