RemotePlugin.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. *
  7. * @license GNU AGPL version 3 or any later version
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License as
  11. * published by the Free Software Foundation, either version 3 of the
  12. * License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. namespace OC\Collaboration\Collaborators;
  24. use OCP\Collaboration\Collaborators\ISearchPlugin;
  25. use OCP\Collaboration\Collaborators\ISearchResult;
  26. use OCP\Collaboration\Collaborators\SearchResultType;
  27. use OCP\Contacts\IManager;
  28. use OCP\Federation\ICloudIdManager;
  29. use OCP\IConfig;
  30. use OCP\IUserManager;
  31. use OCP\IUserSession;
  32. use OCP\Share;
  33. class RemotePlugin implements ISearchPlugin {
  34. protected $shareeEnumeration;
  35. /** @var IManager */
  36. private $contactsManager;
  37. /** @var ICloudIdManager */
  38. private $cloudIdManager;
  39. /** @var IConfig */
  40. private $config;
  41. /** @var IUserManager */
  42. private $userManager;
  43. /** @var string */
  44. private $userId = '';
  45. public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
  46. $this->contactsManager = $contactsManager;
  47. $this->cloudIdManager = $cloudIdManager;
  48. $this->config = $config;
  49. $this->userManager = $userManager;
  50. $user = $userSession->getUser();
  51. if ($user !== null) {
  52. $this->userId = $user->getUID();
  53. }
  54. $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
  55. }
  56. public function search($search, $limit, $offset, ISearchResult $searchResult) {
  57. $result = ['wide' => [], 'exact' => []];
  58. $resultType = new SearchResultType('remotes');
  59. // Search in contacts
  60. //@todo Pagination missing
  61. $addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
  62. foreach ($addressBookContacts as $contact) {
  63. if (isset($contact['isLocalSystemBook'])) {
  64. continue;
  65. }
  66. if (isset($contact['CLOUD'])) {
  67. $cloudIds = $contact['CLOUD'];
  68. if (is_string($cloudIds)) {
  69. $cloudIds = [$cloudIds];
  70. }
  71. $lowerSearch = strtolower($search);
  72. foreach ($cloudIds as $cloudId) {
  73. $cloudIdType = '';
  74. if (\is_array($cloudId)) {
  75. $cloudIdData = $cloudId;
  76. $cloudId = $cloudIdData['value'];
  77. $cloudIdType = $cloudIdData['type'];
  78. }
  79. try {
  80. list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
  81. } catch (\InvalidArgumentException $e) {
  82. continue;
  83. }
  84. $localUser = $this->userManager->get($remoteUser);
  85. /**
  86. * Add local share if remote cloud id matches a local user ones
  87. */
  88. if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId() ) {
  89. $result['wide'][] = [
  90. 'label' => $contact['FN'],
  91. 'uuid' => $contact['UID'],
  92. 'value' => [
  93. 'shareType' => Share::SHARE_TYPE_USER,
  94. 'shareWith' => $remoteUser
  95. ]
  96. ];
  97. }
  98. if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
  99. if (strtolower($cloudId) === $lowerSearch) {
  100. $searchResult->markExactIdMatch($resultType);
  101. }
  102. $result['exact'][] = [
  103. 'label' => $contact['FN'] . " ($cloudId)",
  104. 'uuid' => $contact['UID'],
  105. 'name' => $contact['FN'],
  106. 'type' => $cloudIdType,
  107. 'value' => [
  108. 'shareType' => Share::SHARE_TYPE_REMOTE,
  109. 'shareWith' => $cloudId,
  110. 'server' => $serverUrl,
  111. ],
  112. ];
  113. } else {
  114. $result['wide'][] = [
  115. 'label' => $contact['FN'] . " ($cloudId)",
  116. 'uuid' => $contact['UID'],
  117. 'name' => $contact['FN'],
  118. 'type' => $cloudIdType,
  119. 'value' => [
  120. 'shareType' => Share::SHARE_TYPE_REMOTE,
  121. 'shareWith' => $cloudId,
  122. 'server' => $serverUrl,
  123. ],
  124. ];
  125. }
  126. }
  127. }
  128. }
  129. if (!$this->shareeEnumeration) {
  130. $result['wide'] = [];
  131. } else {
  132. $result['wide'] = array_slice($result['wide'], $offset, $limit);
  133. }
  134. /**
  135. * Add generic share with remote item for valid cloud ids that are not users of the local instance
  136. */
  137. if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
  138. try {
  139. list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
  140. $localUser = $this->userManager->get($remoteUser);
  141. if ($localUser === null || $search !== $localUser->getCloudId()) {
  142. $result['exact'][] = [
  143. 'label' => $search,
  144. 'value' => [
  145. 'shareType' => Share::SHARE_TYPE_REMOTE,
  146. 'shareWith' => $search,
  147. ],
  148. ];
  149. }
  150. } catch (\InvalidArgumentException $e) {
  151. }
  152. }
  153. $searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
  154. return true;
  155. }
  156. /**
  157. * split user and remote from federated cloud id
  158. *
  159. * @param string $address federated share address
  160. * @return array [user, remoteURL]
  161. * @throws \InvalidArgumentException
  162. */
  163. public function splitUserRemote($address) {
  164. try {
  165. $cloudId = $this->cloudIdManager->resolveCloudId($address);
  166. return [$cloudId->getUser(), $cloudId->getRemote()];
  167. } catch (\InvalidArgumentException $e) {
  168. throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
  169. }
  170. }
  171. }