LegacyStoragesService.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Joas Schilling <coding@schilljs.com>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. * @author Robin Appelman <robin@icewind.nl>
  9. * @author Stefan Weil <sw@weilnetz.de>
  10. * @author szaimen <szaimen@e.mail.de>
  11. *
  12. * @license AGPL-3.0
  13. *
  14. * This code is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License, version 3,
  16. * as published by the Free Software Foundation.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU Affero General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Affero General Public License, version 3,
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>
  25. *
  26. */
  27. namespace OCA\Files_External\Service;
  28. use OCA\Files_External\Lib\StorageConfig;
  29. use Psr\Log\LoggerInterface;
  30. /**
  31. * Read mount config from legacy mount.json
  32. */
  33. abstract class LegacyStoragesService {
  34. /** @var BackendService */
  35. protected $backendService;
  36. /**
  37. * Read legacy config data
  38. *
  39. * @return array list of mount configs
  40. */
  41. abstract protected function readLegacyConfig();
  42. /**
  43. * Copy legacy storage options into the given storage config object.
  44. *
  45. * @param StorageConfig $storageConfig storage config to populate
  46. * @param string $mountType mount type
  47. * @param string $applicable applicable user or group
  48. * @param array $storageOptions legacy storage options
  49. *
  50. * @return StorageConfig populated storage config
  51. */
  52. protected function populateStorageConfigWithLegacyOptions(
  53. &$storageConfig,
  54. $mountType,
  55. $applicable,
  56. $storageOptions
  57. ) {
  58. $backend = $this->backendService->getBackend($storageOptions['backend']);
  59. if (!$backend) {
  60. throw new \UnexpectedValueException('Invalid backend ' . $storageOptions['backend']);
  61. }
  62. $storageConfig->setBackend($backend);
  63. if (isset($storageOptions['authMechanism']) && $storageOptions['authMechanism'] !== 'builtin::builtin') {
  64. $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']);
  65. } else {
  66. $authMechanism = $backend->getLegacyAuthMechanism($storageOptions);
  67. $storageOptions['authMechanism'] = 'null'; // to make error handling easier
  68. }
  69. if (!$authMechanism) {
  70. throw new \UnexpectedValueException('Invalid authentication mechanism ' . $storageOptions['authMechanism']);
  71. }
  72. $storageConfig->setAuthMechanism($authMechanism);
  73. $storageConfig->setBackendOptions($storageOptions['options']);
  74. if (isset($storageOptions['mountOptions'])) {
  75. $storageConfig->setMountOptions($storageOptions['mountOptions']);
  76. }
  77. if (!isset($storageOptions['priority'])) {
  78. $storageOptions['priority'] = $backend->getPriority();
  79. }
  80. $storageConfig->setPriority($storageOptions['priority']);
  81. if ($mountType === \OCA\Files_External\MountConfig::MOUNT_TYPE_USER) {
  82. $applicableUsers = $storageConfig->getApplicableUsers();
  83. if ($applicable !== 'all') {
  84. $applicableUsers[] = $applicable;
  85. $storageConfig->setApplicableUsers($applicableUsers);
  86. }
  87. } elseif ($mountType === \OCA\Files_External\MountConfig::MOUNT_TYPE_GROUP) {
  88. $applicableGroups = $storageConfig->getApplicableGroups();
  89. $applicableGroups[] = $applicable;
  90. $storageConfig->setApplicableGroups($applicableGroups);
  91. }
  92. return $storageConfig;
  93. }
  94. /**
  95. * Read the external storage config
  96. *
  97. * @return StorageConfig[] map of storage id to storage config
  98. */
  99. public function getAllStorages() {
  100. $mountPoints = $this->readLegacyConfig();
  101. /**
  102. * Here is the how the horribly messy mount point array looks like
  103. * from the mount.json file:
  104. *
  105. * $storageOptions = $mountPoints[$mountType][$applicable][$mountPath]
  106. *
  107. * - $mountType is either "user" or "group"
  108. * - $applicable is the name of a user or group (or the current user for personal mounts)
  109. * - $mountPath is the mount point path (where the storage must be mounted)
  110. * - $storageOptions is a map of storage options:
  111. * - "priority": storage priority
  112. * - "backend": backend identifier
  113. * - "class": LEGACY backend class name
  114. * - "options": backend-specific options
  115. * - "authMechanism": authentication mechanism identifier
  116. * - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
  117. */
  118. // group by storage id
  119. /** @var StorageConfig[] $storages */
  120. $storages = [];
  121. // for storages without id (legacy), group by config hash for
  122. // later processing
  123. $storagesWithConfigHash = [];
  124. foreach ($mountPoints as $mountType => $applicables) {
  125. foreach ($applicables as $applicable => $mountPaths) {
  126. foreach ($mountPaths as $rootMountPath => $storageOptions) {
  127. $currentStorage = null;
  128. /**
  129. * Flag whether the config that was read already has an id.
  130. * If not, it will use a config hash instead and generate
  131. * a proper id later
  132. *
  133. * @var boolean
  134. */
  135. $hasId = false;
  136. // the root mount point is in the format "/$user/files/the/mount/point"
  137. // we remove the "/$user/files" prefix
  138. $parts = explode('/', ltrim($rootMountPath, '/'), 3);
  139. if (count($parts) < 3) {
  140. // something went wrong, skip
  141. \OC::$server->get(LoggerInterface::class)->error('Could not parse mount point "' . $rootMountPath . '"', ['app' => 'files_external']);
  142. continue;
  143. }
  144. $relativeMountPath = rtrim($parts[2], '/');
  145. // note: we cannot do this after the loop because the decrypted config
  146. // options might be needed for the config hash
  147. $storageOptions['options'] = \OCA\Files_External\MountConfig::decryptPasswords($storageOptions['options']);
  148. if (!isset($storageOptions['backend'])) {
  149. $storageOptions['backend'] = $storageOptions['class']; // legacy compat
  150. }
  151. if (!isset($storageOptions['authMechanism'])) {
  152. $storageOptions['authMechanism'] = null; // ensure config hash works
  153. }
  154. if (isset($storageOptions['id'])) {
  155. $configId = (int)$storageOptions['id'];
  156. if (isset($storages[$configId])) {
  157. $currentStorage = $storages[$configId];
  158. }
  159. $hasId = true;
  160. } else {
  161. // missing id in legacy config, need to generate
  162. // but at this point we don't know the max-id, so use
  163. // first group it by config hash
  164. $storageOptions['mountpoint'] = $rootMountPath;
  165. $configId = \OCA\Files_External\MountConfig::makeConfigHash($storageOptions);
  166. if (isset($storagesWithConfigHash[$configId])) {
  167. $currentStorage = $storagesWithConfigHash[$configId];
  168. }
  169. }
  170. if (is_null($currentStorage)) {
  171. // create new
  172. $currentStorage = new StorageConfig($configId);
  173. $currentStorage->setMountPoint($relativeMountPath);
  174. }
  175. try {
  176. $this->populateStorageConfigWithLegacyOptions(
  177. $currentStorage,
  178. $mountType,
  179. $applicable,
  180. $storageOptions
  181. );
  182. if ($hasId) {
  183. $storages[$configId] = $currentStorage;
  184. } else {
  185. $storagesWithConfigHash[$configId] = $currentStorage;
  186. }
  187. } catch (\UnexpectedValueException $e) {
  188. // don't die if a storage backend doesn't exist
  189. \OC::$server->get(LoggerInterface::class)->error('Could not load storage.', [
  190. 'app' => 'files_external',
  191. 'exception' => $e,
  192. ]);
  193. }
  194. }
  195. }
  196. }
  197. // convert parameter values
  198. foreach ($storages as $storage) {
  199. $storage->getBackend()->validateStorageDefinition($storage);
  200. $storage->getAuthMechanism()->validateStorageDefinition($storage);
  201. }
  202. return $storages;
  203. }
  204. }