File.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OC\Encryption;
  8. use OCA\Files_External\Service\GlobalStoragesService;
  9. use OCP\App\IAppManager;
  10. use OCP\Cache\CappedMemoryCache;
  11. use OCP\Files\IRootFolder;
  12. use OCP\Files\NotFoundException;
  13. use OCP\Share\IManager;
  14. class File implements \OCP\Encryption\IFile {
  15. protected Util $util;
  16. private IRootFolder $rootFolder;
  17. private IManager $shareManager;
  18. /**
  19. * Cache results of already checked folders
  20. * @var CappedMemoryCache<array>
  21. */
  22. protected CappedMemoryCache $cache;
  23. private ?IAppManager $appManager = null;
  24. public function __construct(Util $util,
  25. IRootFolder $rootFolder,
  26. IManager $shareManager) {
  27. $this->util = $util;
  28. $this->cache = new CappedMemoryCache();
  29. $this->rootFolder = $rootFolder;
  30. $this->shareManager = $shareManager;
  31. }
  32. public function getAppManager(): IAppManager {
  33. // Lazy evaluate app manager as it initialize the db too early otherwise
  34. if ($this->appManager) {
  35. return $this->appManager;
  36. }
  37. $this->appManager = \OCP\Server::get(IAppManager::class);
  38. return $this->appManager;
  39. }
  40. /**
  41. * Get list of users with access to the file
  42. *
  43. * @param string $path to the file
  44. * @return array{users: string[], public: bool}
  45. */
  46. public function getAccessList($path) {
  47. // Make sure that a share key is generated for the owner too
  48. [$owner, $ownerPath] = $this->util->getUidAndFilename($path);
  49. // always add owner to the list of users with access to the file
  50. $userIds = [$owner];
  51. if (!$this->util->isFile($owner . '/' . $ownerPath)) {
  52. return ['users' => $userIds, 'public' => false];
  53. }
  54. $ownerPath = substr($ownerPath, strlen('/files'));
  55. $userFolder = $this->rootFolder->getUserFolder($owner);
  56. try {
  57. $file = $userFolder->get($ownerPath);
  58. } catch (NotFoundException $e) {
  59. $file = null;
  60. }
  61. $ownerPath = $this->util->stripPartialFileExtension($ownerPath);
  62. // first get the shares for the parent and cache the result so that we don't
  63. // need to check all parents for every file
  64. $parent = dirname($ownerPath);
  65. $parentNode = $userFolder->get($parent);
  66. if (isset($this->cache[$parent])) {
  67. $resultForParents = $this->cache[$parent];
  68. } else {
  69. $resultForParents = $this->shareManager->getAccessList($parentNode);
  70. $this->cache[$parent] = $resultForParents;
  71. }
  72. $userIds = array_merge($userIds, $resultForParents['users']);
  73. $public = $resultForParents['public'] || $resultForParents['remote'];
  74. // Find out who, if anyone, is sharing the file
  75. if ($file !== null) {
  76. $resultForFile = $this->shareManager->getAccessList($file, false);
  77. $userIds = array_merge($userIds, $resultForFile['users']);
  78. $public = $resultForFile['public'] || $resultForFile['remote'] || $public;
  79. }
  80. // check if it is a group mount
  81. if ($this->getAppManager()->isEnabledForUser('files_external')) {
  82. /** @var GlobalStoragesService $storageService */
  83. $storageService = \OC::$server->get(GlobalStoragesService::class);
  84. $storages = $storageService->getAllStorages();
  85. foreach ($storages as $storage) {
  86. if ($storage->getMountPoint() == substr($ownerPath, 0, strlen($storage->getMountPoint()))) {
  87. $mountedFor = $this->util->getUserWithAccessToMountPoint($storage->getApplicableUsers(), $storage->getApplicableGroups());
  88. $userIds = array_merge($userIds, $mountedFor);
  89. }
  90. }
  91. }
  92. // Remove duplicate UIDs
  93. $uniqueUserIds = array_unique($userIds);
  94. return ['users' => $uniqueUserIds, 'public' => $public];
  95. }
  96. }