Import.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\Files_External\Command;
  8. use OC\Core\Command\Base;
  9. use OC\User\NoUserException;
  10. use OCA\Files_External\Lib\StorageConfig;
  11. use OCA\Files_External\Service\BackendService;
  12. use OCA\Files_External\Service\GlobalStoragesService;
  13. use OCA\Files_External\Service\ImportLegacyStoragesService;
  14. use OCA\Files_External\Service\StoragesService;
  15. use OCA\Files_External\Service\UserStoragesService;
  16. use OCP\IUserManager;
  17. use OCP\IUserSession;
  18. use Symfony\Component\Console\Input\ArrayInput;
  19. use Symfony\Component\Console\Input\InputArgument;
  20. use Symfony\Component\Console\Input\InputInterface;
  21. use Symfony\Component\Console\Input\InputOption;
  22. use Symfony\Component\Console\Output\OutputInterface;
  23. class Import extends Base {
  24. public function __construct(
  25. private GlobalStoragesService $globalService,
  26. private UserStoragesService $userService,
  27. private IUserSession $userSession,
  28. private IUserManager $userManager,
  29. private ImportLegacyStoragesService $importLegacyStorageService,
  30. private BackendService $backendService,
  31. ) {
  32. parent::__construct();
  33. }
  34. protected function configure(): void {
  35. $this
  36. ->setName('files_external:import')
  37. ->setDescription('Import mount configurations')
  38. ->addOption(
  39. 'user',
  40. '',
  41. InputOption::VALUE_OPTIONAL,
  42. 'user to add the mount configurations for, if not set the mount will be added as system mount'
  43. )
  44. ->addArgument(
  45. 'path',
  46. InputArgument::REQUIRED,
  47. 'path to a json file containing the mounts to import, use "-" to read from stdin'
  48. )
  49. ->addOption(
  50. 'dry',
  51. '',
  52. InputOption::VALUE_NONE,
  53. 'Don\'t save the imported mounts, only list the new mounts'
  54. );
  55. parent::configure();
  56. }
  57. protected function execute(InputInterface $input, OutputInterface $output): int {
  58. $user = (string) $input->getOption('user');
  59. $path = $input->getArgument('path');
  60. if ($path === '-') {
  61. $json = file_get_contents('php://stdin');
  62. } else {
  63. if (!file_exists($path)) {
  64. $output->writeln('<error>File not found: ' . $path . '</error>');
  65. return self::FAILURE;
  66. }
  67. $json = file_get_contents($path);
  68. }
  69. if (!is_string($json) || strlen($json) < 2) {
  70. $output->writeln('<error>Error while reading json</error>');
  71. return self::FAILURE;
  72. }
  73. $data = json_decode($json, true);
  74. if (!is_array($data)) {
  75. $output->writeln('<error>Error while parsing json</error>');
  76. return self::FAILURE;
  77. }
  78. $isLegacy = isset($data['user']) || isset($data['group']);
  79. if ($isLegacy) {
  80. $this->importLegacyStorageService->setData($data);
  81. $mounts = $this->importLegacyStorageService->getAllStorages();
  82. foreach ($mounts as $mount) {
  83. if ($mount->getBackendOption('password') === false) {
  84. $output->writeln('<error>Failed to decrypt password</error>');
  85. return self::FAILURE;
  86. }
  87. }
  88. } else {
  89. if (!isset($data[0])) { //normalize to an array of mounts
  90. $data = [$data];
  91. }
  92. $mounts = array_map([$this, 'parseData'], $data);
  93. }
  94. if ($user) {
  95. // ensure applicables are correct for personal mounts
  96. foreach ($mounts as $mount) {
  97. $mount->setApplicableGroups([]);
  98. $mount->setApplicableUsers([$user]);
  99. }
  100. }
  101. $storageService = $this->getStorageService($user);
  102. $existingMounts = $storageService->getAllStorages();
  103. foreach ($mounts as $mount) {
  104. foreach ($existingMounts as $existingMount) {
  105. if (
  106. $existingMount->getMountPoint() === $mount->getMountPoint() &&
  107. $existingMount->getApplicableGroups() === $mount->getApplicableGroups() &&
  108. $existingMount->getApplicableUsers() === $mount->getApplicableUsers() &&
  109. $existingMount->getBackendOptions() === $mount->getBackendOptions()
  110. ) {
  111. $output->writeln("<error>Duplicate mount (" . $mount->getMountPoint() . ")</error>");
  112. return self::FAILURE;
  113. }
  114. }
  115. }
  116. if ($input->getOption('dry')) {
  117. if (count($mounts) === 0) {
  118. $output->writeln('<error>No mounts to be imported</error>');
  119. return self::FAILURE;
  120. }
  121. $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
  122. $listInput = new ArrayInput([], $listCommand->getDefinition());
  123. $listInput->setOption('output', $input->getOption('output'));
  124. $listInput->setOption('show-password', true);
  125. $listCommand->listMounts($user, $mounts, $listInput, $output);
  126. } else {
  127. foreach ($mounts as $mount) {
  128. $storageService->addStorage($mount);
  129. }
  130. }
  131. return self::SUCCESS;
  132. }
  133. private function parseData(array $data): StorageConfig {
  134. $mount = new StorageConfig($data['mount_id']);
  135. $mount->setMountPoint($data['mount_point']);
  136. $mount->setBackend($this->getBackendByClass($data['storage']));
  137. $authBackend = $this->backendService->getAuthMechanism($data['authentication_type']);
  138. $mount->setAuthMechanism($authBackend);
  139. $mount->setBackendOptions($data['configuration']);
  140. $mount->setMountOptions($data['options']);
  141. $mount->setApplicableUsers($data['applicable_users'] ?? []);
  142. $mount->setApplicableGroups($data['applicable_groups'] ?? []);
  143. return $mount;
  144. }
  145. private function getBackendByClass(string $className) {
  146. $backends = $this->backendService->getBackends();
  147. foreach ($backends as $backend) {
  148. if ($backend->getStorageClass() === $className) {
  149. return $backend;
  150. }
  151. }
  152. }
  153. protected function getStorageService(string $userId): StoragesService {
  154. if (empty($userId)) {
  155. return $this->globalService;
  156. }
  157. $user = $this->userManager->get($userId);
  158. if (is_null($user)) {
  159. throw new NoUserException("user $userId not found");
  160. }
  161. $this->userSession->setUser($user);
  162. return $this->userService;
  163. }
  164. }