LegacyStoragesService.php 7.4 KB

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