diff options
author | Robin Appelman <robin@icewind.nl> | 2025-02-28 17:42:55 +0100 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2025-06-06 17:12:33 +0200 |
commit | b313aaea7ef96b3ae909cdc6b87af9a354e5db4b (patch) | |
tree | 1f83653525a4ab582327301900b70b393a82e143 | |
parent | 92c97c3447437690389dd7bf94ccba429abbb03e (diff) | |
download | nextcloud-server-home-folder-readonly.tar.gz nextcloud-server-home-folder-readonly.zip |
feat: mark homefolder as overwritten when an external storage mounted at / existshome-folder-readonly
Signed-off-by: Robin Appelman <robin@icewind.nl>
12 files changed, 88 insertions, 13 deletions
diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index e746f052619..8c30054b73b 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -14,7 +14,7 @@ This application enables administrators to configure connections to external sto External storage can be configured using the GUI or at the command line. This second option provides the administration with more flexibility for configuring bulk external storage mounts and setting mount priorities. More information is available in the external storage GUI documentation and the external storage Configuration File documentation. </description> - <version>1.24.0</version> + <version>1.25.0</version> <licence>agpl</licence> <author>Robin Appelman</author> <author>Michael Gapczynski</author> diff --git a/apps/files_external/composer/composer/autoload_classmap.php b/apps/files_external/composer/composer/autoload_classmap.php index 90f41f0e920..7492884d9e1 100644 --- a/apps/files_external/composer/composer/autoload_classmap.php +++ b/apps/files_external/composer/composer/autoload_classmap.php @@ -108,6 +108,7 @@ return array( '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 7b5eb5feabe..da24e8bc60a 100644 --- a/apps/files_external/composer/composer/autoload_static.php +++ b/apps/files_external/composer/composer/autoload_static.php @@ -123,6 +123,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 00000000000..71af435f93e --- /dev/null +++ b/apps/files_external/lib/Migration/Version1025Date20250228162604.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\Files_External\Migration; + +use Closure; +use OCA\Files_External\Service\DBConfigService; +use OCP\DB\ISchemaWrapper; +use OCP\IAppConfig; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Check for any external storage overwriting the home folder + */ +class Version1025Date20250228162604 extends SimpleMigrationStep { + public function __construct( + private DBConfigService $dbConfig, + private IAppConfig $appConfig, + ) { + } + + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + if ($this->dbConfig->hasHomeFolderOverwriteMount()) { + $this->appConfig->setValueBool('files', 'homeFolderOverwritten', true); + } + } +} diff --git a/apps/files_external/lib/Service/DBConfigService.php b/apps/files_external/lib/Service/DBConfigService.php index 3820f6b0d96..9e72eb62971 100644 --- a/apps/files_external/lib/Service/DBConfigService.php +++ b/apps/files_external/lib/Service/DBConfigService.php @@ -4,6 +4,7 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OCA\Files_External\Service; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; @@ -63,16 +64,16 @@ class DBConfigService { ->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); @@ -93,8 +94,8 @@ class DBConfigService { ->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(); @@ -226,7 +227,7 @@ class DBConfigService { '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(); @@ -497,4 +498,19 @@ class DBConfigService { return $value; } } + + /** + * Check if any mountpoint is configured that overwrite the home folder + * + * @return bool + */ + 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 (bool)$result->fetchColumn(); + } } diff --git a/apps/files_external/lib/Service/StoragesService.php b/apps/files_external/lib/Service/StoragesService.php index 73642d85f88..29fa3902ae5 100644 --- a/apps/files_external/lib/Service/StoragesService.php +++ b/apps/files_external/lib/Service/StoragesService.php @@ -19,6 +19,7 @@ use OCP\EventDispatcher\IEventDispatcher; 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; @@ -39,6 +40,7 @@ abstract class StoragesService { protected DBConfigService $dbConfig, protected IUserMountCache $userMountCache, protected IEventDispatcher $eventDispatcher, + protected IAppConfig $appConfig, ) { } @@ -424,6 +426,10 @@ abstract class StoragesService { } } + if ($this->dbConfig->hasHomeFolderOverwriteMount()) { + $this->appConfig->setValueBool('files', 'homeFolderOverwritten', true); + } + return $this->getStorage($id); } diff --git a/apps/files_external/lib/Service/UserGlobalStoragesService.php b/apps/files_external/lib/Service/UserGlobalStoragesService.php index 01bc91ef3ff..f5feb1b0a98 100644 --- a/apps/files_external/lib/Service/UserGlobalStoragesService.php +++ b/apps/files_external/lib/Service/UserGlobalStoragesService.php @@ -9,6 +9,7 @@ namespace OCA\Files_External\Service; 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; @@ -35,8 +36,9 @@ class UserGlobalStoragesService extends GlobalStoragesService { 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 defa97451cd..a0ffa2fdbb1 100644 --- a/apps/files_external/lib/Service/UserStoragesService.php +++ b/apps/files_external/lib/Service/UserStoragesService.php @@ -12,6 +12,7 @@ use OCA\Files_External\MountConfig; use OCA\Files_External\NotFoundException; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; +use OCP\IAppConfig; use OCP\IUserSession; /** @@ -36,9 +37,10 @@ class UserStoragesService extends StoragesService { 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 47be54a02d4..1ca75bb2332 100644 --- a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php @@ -19,7 +19,7 @@ use OCA\Files_External\Service\GlobalStoragesService; 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 a5cffd45ec2..8c916b8a456 100644 --- a/apps/files_external/tests/Service/StoragesServiceTestCase.php +++ b/apps/files_external/tests/Service/StoragesServiceTestCase.php @@ -28,6 +28,7 @@ use OCP\Files\Cache\ICache; 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; @@ -63,6 +64,10 @@ abstract class StoragesServiceTestCase extends \Test\TestCase { protected static array $hookCalls; protected IUserMountCache&MockObject $mountCache; protected IEventDispatcher&MockObject $eventDispatcher; + /** + * @var \PHPUnit\Framework\MockObject\MockObject|IAppConfig + */ + protected IAppConfig $appConfig; protected function setUp(): void { parent::setUp(); @@ -77,6 +82,7 @@ abstract class StoragesServiceTestCase extends \Test\TestCase { $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 1ec4e56bd9e..92c99519ff4 100644 --- a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php @@ -74,6 +74,7 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { $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 53d7f5960e8..39357f997aa 100644 --- a/apps/files_external/tests/Service/UserStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserStoragesServiceTest.php @@ -34,7 +34,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); @@ -47,7 +47,7 @@ class UserStoragesServiceTest extends StoragesServiceTestCase { ->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() { |