You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CloudIdManager.php 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
  5. *
  6. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  7. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  8. * @author Guillaume Virlet <github@virlet.org>
  9. * @author Joas Schilling <coding@schilljs.com>
  10. * @author Robin Appelman <robin@icewind.nl>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. *
  13. * @license GNU AGPL version 3 or any later version
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License as
  17. * published by the Free Software Foundation, either version 3 of the
  18. * License, or (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU Affero General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Affero General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. *
  28. */
  29. namespace OC\Federation;
  30. use OCP\Contacts\IManager;
  31. use OCP\Federation\ICloudId;
  32. use OCP\Federation\ICloudIdManager;
  33. use OCP\IURLGenerator;
  34. use OCP\IUserManager;
  35. class CloudIdManager implements ICloudIdManager {
  36. /** @var IManager */
  37. private $contactsManager;
  38. /** @var IURLGenerator */
  39. private $urlGenerator;
  40. /** @var IUserManager */
  41. private $userManager;
  42. public function __construct(IManager $contactsManager, IURLGenerator $urlGenerator, IUserManager $userManager) {
  43. $this->contactsManager = $contactsManager;
  44. $this->urlGenerator = $urlGenerator;
  45. $this->userManager = $userManager;
  46. }
  47. /**
  48. * @param string $cloudId
  49. * @return ICloudId
  50. * @throws \InvalidArgumentException
  51. */
  52. public function resolveCloudId(string $cloudId): ICloudId {
  53. // TODO magic here to get the url and user instead of just splitting on @
  54. if (!$this->isValidCloudId($cloudId)) {
  55. throw new \InvalidArgumentException('Invalid cloud id');
  56. }
  57. // Find the first character that is not allowed in user names
  58. $id = $this->fixRemoteURL($cloudId);
  59. $posSlash = strpos($id, '/');
  60. $posColon = strpos($id, ':');
  61. if ($posSlash === false && $posColon === false) {
  62. $invalidPos = \strlen($id);
  63. } elseif ($posSlash === false) {
  64. $invalidPos = $posColon;
  65. } elseif ($posColon === false) {
  66. $invalidPos = $posSlash;
  67. } else {
  68. $invalidPos = min($posSlash, $posColon);
  69. }
  70. $lastValidAtPos = strrpos($id, '@', $invalidPos - strlen($id));
  71. if ($lastValidAtPos !== false) {
  72. $user = substr($id, 0, $lastValidAtPos);
  73. $remote = substr($id, $lastValidAtPos + 1);
  74. if (!empty($user) && !empty($remote)) {
  75. return new CloudId($id, $user, $remote, $this->getDisplayNameFromContact($id));
  76. }
  77. }
  78. throw new \InvalidArgumentException('Invalid cloud id');
  79. }
  80. protected function getDisplayNameFromContact(string $cloudId): ?string {
  81. $addressBookEntries = $this->contactsManager->search($cloudId, ['CLOUD']);
  82. foreach ($addressBookEntries as $entry) {
  83. if (isset($entry['CLOUD'])) {
  84. foreach ($entry['CLOUD'] as $cloudID) {
  85. if ($cloudID === $cloudId) {
  86. // Warning, if user decides to make his full name local only,
  87. // no FN is found on federated servers
  88. if (isset($entry['FN'])) {
  89. return $entry['FN'];
  90. } else {
  91. return $cloudID;
  92. }
  93. }
  94. }
  95. }
  96. }
  97. return null;
  98. }
  99. /**
  100. * @param string $user
  101. * @param string|null $remote
  102. * @return CloudId
  103. */
  104. public function getCloudId(string $user, ?string $remote): ICloudId {
  105. if ($remote === null) {
  106. $remote = rtrim($this->removeProtocolFromUrl($this->urlGenerator->getAbsoluteURL('/')), '/');
  107. $fixedRemote = $this->fixRemoteURL($remote);
  108. $localUser = $this->userManager->get($user);
  109. $displayName = !is_null($localUser) ? $localUser->getDisplayName() : '';
  110. } else {
  111. // TODO check what the correct url is for remote (asking the remote)
  112. $fixedRemote = $this->fixRemoteURL($remote);
  113. $host = $this->removeProtocolFromUrl($fixedRemote);
  114. $displayName = $this->getDisplayNameFromContact($user . '@' . $host);
  115. }
  116. $id = $user . '@' . $remote;
  117. return new CloudId($id, $user, $fixedRemote, $displayName);
  118. }
  119. /**
  120. * @param string $url
  121. * @return string
  122. */
  123. private function removeProtocolFromUrl($url) {
  124. if (strpos($url, 'https://') === 0) {
  125. return substr($url, strlen('https://'));
  126. } elseif (strpos($url, 'http://') === 0) {
  127. return substr($url, strlen('http://'));
  128. }
  129. return $url;
  130. }
  131. /**
  132. * Strips away a potential file names and trailing slashes:
  133. * - http://localhost
  134. * - http://localhost/
  135. * - http://localhost/index.php
  136. * - http://localhost/index.php/s/{shareToken}
  137. *
  138. * all return: http://localhost
  139. *
  140. * @param string $remote
  141. * @return string
  142. */
  143. protected function fixRemoteURL(string $remote): string {
  144. $remote = str_replace('\\', '/', $remote);
  145. if ($fileNamePosition = strpos($remote, '/index.php')) {
  146. $remote = substr($remote, 0, $fileNamePosition);
  147. }
  148. $remote = rtrim($remote, '/');
  149. return $remote;
  150. }
  151. /**
  152. * @param string $cloudId
  153. * @return bool
  154. */
  155. public function isValidCloudId(string $cloudId): bool {
  156. return strpos($cloudId, '@') !== false;
  157. }
  158. }