CloudFederationProviderFiles.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OCA\FederatedFileSharing\OCM;
  7. use OC\AppFramework\Http;
  8. use OC\Files\Filesystem;
  9. use OCA\FederatedFileSharing\AddressHandler;
  10. use OCA\FederatedFileSharing\FederatedShareProvider;
  11. use OCA\Files_Sharing\Activity\Providers\RemoteShares;
  12. use OCA\Files_Sharing\External\Manager;
  13. use OCA\GlobalSiteSelector\Service\SlaveService;
  14. use OCP\Activity\IManager as IActivityManager;
  15. use OCP\App\IAppManager;
  16. use OCP\AppFramework\QueryException;
  17. use OCP\Constants;
  18. use OCP\Federation\Exceptions\ActionNotSupportedException;
  19. use OCP\Federation\Exceptions\AuthenticationFailedException;
  20. use OCP\Federation\Exceptions\BadRequestException;
  21. use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
  22. use OCP\Federation\ICloudFederationFactory;
  23. use OCP\Federation\ICloudFederationProvider;
  24. use OCP\Federation\ICloudFederationProviderManager;
  25. use OCP\Federation\ICloudFederationShare;
  26. use OCP\Federation\ICloudIdManager;
  27. use OCP\Files\IFilenameValidator;
  28. use OCP\Files\NotFoundException;
  29. use OCP\HintException;
  30. use OCP\IConfig;
  31. use OCP\IDBConnection;
  32. use OCP\IGroupManager;
  33. use OCP\IURLGenerator;
  34. use OCP\IUserManager;
  35. use OCP\Notification\IManager as INotificationManager;
  36. use OCP\Server;
  37. use OCP\Share\Exceptions\ShareNotFound;
  38. use OCP\Share\IManager;
  39. use OCP\Share\IShare;
  40. use OCP\Util;
  41. use Psr\Log\LoggerInterface;
  42. class CloudFederationProviderFiles implements ICloudFederationProvider {
  43. /**
  44. * CloudFederationProvider constructor.
  45. */
  46. public function __construct(
  47. private IAppManager $appManager,
  48. private FederatedShareProvider $federatedShareProvider,
  49. private AddressHandler $addressHandler,
  50. private IUserManager $userManager,
  51. private IManager $shareManager,
  52. private ICloudIdManager $cloudIdManager,
  53. private IActivityManager $activityManager,
  54. private INotificationManager $notificationManager,
  55. private IURLGenerator $urlGenerator,
  56. private ICloudFederationFactory $cloudFederationFactory,
  57. private ICloudFederationProviderManager $cloudFederationProviderManager,
  58. private IDBConnection $connection,
  59. private IGroupManager $groupManager,
  60. private IConfig $config,
  61. private Manager $externalShareManager,
  62. private LoggerInterface $logger,
  63. private IFilenameValidator $filenameValidator,
  64. ) {
  65. }
  66. /**
  67. * @return string
  68. */
  69. public function getShareType() {
  70. return 'file';
  71. }
  72. /**
  73. * share received from another server
  74. *
  75. * @param ICloudFederationShare $share
  76. * @return string provider specific unique ID of the share
  77. *
  78. * @throws ProviderCouldNotAddShareException
  79. * @throws QueryException
  80. * @throws HintException
  81. * @since 14.0.0
  82. */
  83. public function shareReceived(ICloudFederationShare $share) {
  84. if (!$this->isS2SEnabled(true)) {
  85. throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
  86. }
  87. $protocol = $share->getProtocol();
  88. if ($protocol['name'] !== 'webdav') {
  89. throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
  90. }
  91. [$ownerUid, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
  92. // for backward compatibility make sure that the remote url stored in the
  93. // database ends with a trailing slash
  94. if (!str_ends_with($remote, '/')) {
  95. $remote = $remote . '/';
  96. }
  97. $token = $share->getShareSecret();
  98. $name = $share->getResourceName();
  99. $owner = $share->getOwnerDisplayName();
  100. $sharedBy = $share->getSharedByDisplayName();
  101. $shareWith = $share->getShareWith();
  102. $remoteId = $share->getProviderId();
  103. $sharedByFederatedId = $share->getSharedBy();
  104. $ownerFederatedId = $share->getOwner();
  105. $shareType = $this->mapShareTypeToNextcloud($share->getShareType());
  106. // if no explicit information about the person who created the share was send
  107. // we assume that the share comes from the owner
  108. if ($sharedByFederatedId === null) {
  109. $sharedBy = $owner;
  110. $sharedByFederatedId = $ownerFederatedId;
  111. }
  112. if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
  113. if (!$this->filenameValidator->isFilenameValid($name)) {
  114. throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
  115. }
  116. // FIXME this should be a method in the user management instead
  117. if ($shareType === IShare::TYPE_USER) {
  118. $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
  119. Util::emitHook(
  120. '\OCA\Files_Sharing\API\Server2Server',
  121. 'preLoginNameUsedAsUserName',
  122. ['uid' => &$shareWith]
  123. );
  124. $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
  125. if (!$this->userManager->userExists($shareWith)) {
  126. throw new ProviderCouldNotAddShareException('User does not exists', '', Http::STATUS_BAD_REQUEST);
  127. }
  128. \OC_Util::setupFS($shareWith);
  129. }
  130. if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
  131. throw new ProviderCouldNotAddShareException('Group does not exists', '', Http::STATUS_BAD_REQUEST);
  132. }
  133. try {
  134. $this->externalShareManager->addShare($remote, $token, '', $name, $owner, $shareType, false, $shareWith, $remoteId);
  135. $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
  136. // get DisplayName about the owner of the share
  137. $ownerDisplayName = $this->getUserDisplayName($ownerFederatedId);
  138. if ($shareType === IShare::TYPE_USER) {
  139. $event = $this->activityManager->generateEvent();
  140. $event->setApp('files_sharing')
  141. ->setType('remote_share')
  142. ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
  143. ->setAffectedUser($shareWith)
  144. ->setObject('remote_share', $shareId, $name);
  145. \OC::$server->getActivityManager()->publish($event);
  146. $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
  147. } else {
  148. $groupMembers = $this->groupManager->get($shareWith)->getUsers();
  149. foreach ($groupMembers as $user) {
  150. $event = $this->activityManager->generateEvent();
  151. $event->setApp('files_sharing')
  152. ->setType('remote_share')
  153. ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
  154. ->setAffectedUser($user->getUID())
  155. ->setObject('remote_share', $shareId, $name);
  156. \OC::$server->getActivityManager()->publish($event);
  157. $this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
  158. }
  159. }
  160. return $shareId;
  161. } catch (\Exception $e) {
  162. $this->logger->error('Server can not add remote share.', [
  163. 'app' => 'files_sharing',
  164. 'exception' => $e,
  165. ]);
  166. throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
  167. }
  168. }
  169. throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
  170. }
  171. /**
  172. * notification received from another server
  173. *
  174. * @param string $notificationType (e.g. SHARE_ACCEPTED)
  175. * @param string $providerId id of the share
  176. * @param array $notification payload of the notification
  177. * @return array<string> data send back to the sender
  178. *
  179. * @throws ActionNotSupportedException
  180. * @throws AuthenticationFailedException
  181. * @throws BadRequestException
  182. * @throws HintException
  183. * @since 14.0.0
  184. */
  185. public function notificationReceived($notificationType, $providerId, array $notification) {
  186. switch ($notificationType) {
  187. case 'SHARE_ACCEPTED':
  188. return $this->shareAccepted($providerId, $notification);
  189. case 'SHARE_DECLINED':
  190. return $this->shareDeclined($providerId, $notification);
  191. case 'SHARE_UNSHARED':
  192. return $this->unshare($providerId, $notification);
  193. case 'REQUEST_RESHARE':
  194. return $this->reshareRequested($providerId, $notification);
  195. case 'RESHARE_UNDO':
  196. return $this->undoReshare($providerId, $notification);
  197. case 'RESHARE_CHANGE_PERMISSION':
  198. return $this->updateResharePermissions($providerId, $notification);
  199. }
  200. throw new BadRequestException([$notificationType]);
  201. }
  202. /**
  203. * map OCM share type (strings) to Nextcloud internal share types (integer)
  204. *
  205. * @param string $shareType
  206. * @return int
  207. */
  208. private function mapShareTypeToNextcloud($shareType) {
  209. $result = IShare::TYPE_USER;
  210. if ($shareType === 'group') {
  211. $result = IShare::TYPE_GROUP;
  212. }
  213. return $result;
  214. }
  215. private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $displayName): void {
  216. $notification = $this->notificationManager->createNotification();
  217. $notification->setApp('files_sharing')
  218. ->setUser($shareWith)
  219. ->setDateTime(new \DateTime())
  220. ->setObject('remote_share', $shareId)
  221. ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/'), $displayName]);
  222. $declineAction = $notification->createAction();
  223. $declineAction->setLabel('decline')
  224. ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
  225. $notification->addAction($declineAction);
  226. $acceptAction = $notification->createAction();
  227. $acceptAction->setLabel('accept')
  228. ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
  229. $notification->addAction($acceptAction);
  230. $this->notificationManager->notify($notification);
  231. }
  232. /**
  233. * process notification that the recipient accepted a share
  234. *
  235. * @param string $id
  236. * @param array $notification
  237. * @return array<string>
  238. * @throws ActionNotSupportedException
  239. * @throws AuthenticationFailedException
  240. * @throws BadRequestException
  241. * @throws HintException
  242. */
  243. private function shareAccepted($id, array $notification) {
  244. if (!$this->isS2SEnabled()) {
  245. throw new ActionNotSupportedException('Server does not support federated cloud sharing');
  246. }
  247. if (!isset($notification['sharedSecret'])) {
  248. throw new BadRequestException(['sharedSecret']);
  249. }
  250. $token = $notification['sharedSecret'];
  251. $share = $this->federatedShareProvider->getShareById($id);
  252. $this->verifyShare($share, $token);
  253. $this->executeAcceptShare($share);
  254. if ($share->getShareOwner() !== $share->getSharedBy()) {
  255. [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
  256. $remoteId = $this->federatedShareProvider->getRemoteId($share);
  257. $notification = $this->cloudFederationFactory->getCloudFederationNotification();
  258. $notification->setMessage(
  259. 'SHARE_ACCEPTED',
  260. 'file',
  261. $remoteId,
  262. [
  263. 'sharedSecret' => $token,
  264. 'message' => 'Recipient accepted the re-share'
  265. ]
  266. );
  267. $this->cloudFederationProviderManager->sendNotification($remote, $notification);
  268. }
  269. return [];
  270. }
  271. /**
  272. * @param IShare $share
  273. * @throws ShareNotFound
  274. */
  275. protected function executeAcceptShare(IShare $share) {
  276. try {
  277. $fileId = (int)$share->getNode()->getId();
  278. [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
  279. } catch (\Exception $e) {
  280. throw new ShareNotFound();
  281. }
  282. $event = $this->activityManager->generateEvent();
  283. $event->setApp('files_sharing')
  284. ->setType('remote_share')
  285. ->setAffectedUser($this->getCorrectUid($share))
  286. ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
  287. ->setObject('files', $fileId, $file)
  288. ->setLink($link);
  289. $this->activityManager->publish($event);
  290. }
  291. /**
  292. * process notification that the recipient declined a share
  293. *
  294. * @param string $id
  295. * @param array $notification
  296. * @return array<string>
  297. * @throws ActionNotSupportedException
  298. * @throws AuthenticationFailedException
  299. * @throws BadRequestException
  300. * @throws ShareNotFound
  301. * @throws HintException
  302. *
  303. */
  304. protected function shareDeclined($id, array $notification) {
  305. if (!$this->isS2SEnabled()) {
  306. throw new ActionNotSupportedException('Server does not support federated cloud sharing');
  307. }
  308. if (!isset($notification['sharedSecret'])) {
  309. throw new BadRequestException(['sharedSecret']);
  310. }
  311. $token = $notification['sharedSecret'];
  312. $share = $this->federatedShareProvider->getShareById($id);
  313. $this->verifyShare($share, $token);
  314. if ($share->getShareOwner() !== $share->getSharedBy()) {
  315. [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
  316. $remoteId = $this->federatedShareProvider->getRemoteId($share);
  317. $notification = $this->cloudFederationFactory->getCloudFederationNotification();
  318. $notification->setMessage(
  319. 'SHARE_DECLINED',
  320. 'file',
  321. $remoteId,
  322. [
  323. 'sharedSecret' => $token,
  324. 'message' => 'Recipient declined the re-share'
  325. ]
  326. );
  327. $this->cloudFederationProviderManager->sendNotification($remote, $notification);
  328. }
  329. $this->executeDeclineShare($share);
  330. return [];
  331. }
  332. /**
  333. * delete declined share and create a activity
  334. *
  335. * @param IShare $share
  336. * @throws ShareNotFound
  337. */
  338. protected function executeDeclineShare(IShare $share) {
  339. $this->federatedShareProvider->removeShareFromTable($share);
  340. try {
  341. $fileId = (int)$share->getNode()->getId();
  342. [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
  343. } catch (\Exception $e) {
  344. throw new ShareNotFound();
  345. }
  346. $event = $this->activityManager->generateEvent();
  347. $event->setApp('files_sharing')
  348. ->setType('remote_share')
  349. ->setAffectedUser($this->getCorrectUid($share))
  350. ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
  351. ->setObject('files', $fileId, $file)
  352. ->setLink($link);
  353. $this->activityManager->publish($event);
  354. }
  355. /**
  356. * received the notification that the owner unshared a file from you
  357. *
  358. * @param string $id
  359. * @param array $notification
  360. * @return array<string>
  361. * @throws AuthenticationFailedException
  362. * @throws BadRequestException
  363. */
  364. private function undoReshare($id, array $notification) {
  365. if (!isset($notification['sharedSecret'])) {
  366. throw new BadRequestException(['sharedSecret']);
  367. }
  368. $token = $notification['sharedSecret'];
  369. $share = $this->federatedShareProvider->getShareById($id);
  370. $this->verifyShare($share, $token);
  371. $this->federatedShareProvider->removeShareFromTable($share);
  372. return [];
  373. }
  374. /**
  375. * unshare file from self
  376. *
  377. * @param string $id
  378. * @param array $notification
  379. * @return array<string>
  380. * @throws ActionNotSupportedException
  381. * @throws BadRequestException
  382. */
  383. private function unshare($id, array $notification) {
  384. if (!$this->isS2SEnabled(true)) {
  385. throw new ActionNotSupportedException('incoming shares disabled!');
  386. }
  387. if (!isset($notification['sharedSecret'])) {
  388. throw new BadRequestException(['sharedSecret']);
  389. }
  390. $token = $notification['sharedSecret'];
  391. $qb = $this->connection->getQueryBuilder();
  392. $qb->select('*')
  393. ->from('share_external')
  394. ->where(
  395. $qb->expr()->andX(
  396. $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
  397. $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
  398. )
  399. );
  400. $result = $qb->executeQuery();
  401. $share = $result->fetch();
  402. $result->closeCursor();
  403. if ($token && $id && !empty($share)) {
  404. $remote = $this->cleanupRemote($share['remote']);
  405. $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
  406. $mountpoint = $share['mountpoint'];
  407. $user = $share['user'];
  408. $qb = $this->connection->getQueryBuilder();
  409. $qb->delete('share_external')
  410. ->where(
  411. $qb->expr()->andX(
  412. $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
  413. $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
  414. )
  415. );
  416. $qb->executeStatement();
  417. // delete all child in case of a group share
  418. $qb = $this->connection->getQueryBuilder();
  419. $qb->delete('share_external')
  420. ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
  421. $qb->executeStatement();
  422. $ownerDisplayName = $this->getUserDisplayName($owner->getId());
  423. if ((int)$share['share_type'] === IShare::TYPE_USER) {
  424. if ($share['accepted']) {
  425. $path = trim($mountpoint, '/');
  426. } else {
  427. $path = trim($share['name'], '/');
  428. }
  429. $notification = $this->notificationManager->createNotification();
  430. $notification->setApp('files_sharing')
  431. ->setUser($share['user'])
  432. ->setObject('remote_share', (string)$share['id']);
  433. $this->notificationManager->markProcessed($notification);
  434. $event = $this->activityManager->generateEvent();
  435. $event->setApp('files_sharing')
  436. ->setType('remote_share')
  437. ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path, $ownerDisplayName])
  438. ->setAffectedUser($user)
  439. ->setObject('remote_share', (int)$share['id'], $path);
  440. \OC::$server->getActivityManager()->publish($event);
  441. }
  442. }
  443. return [];
  444. }
  445. private function cleanupRemote($remote) {
  446. $remote = substr($remote, strpos($remote, '://') + 3);
  447. return rtrim($remote, '/');
  448. }
  449. /**
  450. * recipient of a share request to re-share the file with another user
  451. *
  452. * @param string $id
  453. * @param array $notification
  454. * @return array<string>
  455. * @throws AuthenticationFailedException
  456. * @throws BadRequestException
  457. * @throws ProviderCouldNotAddShareException
  458. * @throws ShareNotFound
  459. */
  460. protected function reshareRequested($id, array $notification) {
  461. if (!isset($notification['sharedSecret'])) {
  462. throw new BadRequestException(['sharedSecret']);
  463. }
  464. $token = $notification['sharedSecret'];
  465. if (!isset($notification['shareWith'])) {
  466. throw new BadRequestException(['shareWith']);
  467. }
  468. $shareWith = $notification['shareWith'];
  469. if (!isset($notification['senderId'])) {
  470. throw new BadRequestException(['senderId']);
  471. }
  472. $senderId = $notification['senderId'];
  473. $share = $this->federatedShareProvider->getShareById($id);
  474. // We have to respect the default share permissions
  475. $permissions = $share->getPermissions() & (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
  476. $share->setPermissions($permissions);
  477. // don't allow to share a file back to the owner
  478. try {
  479. [$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
  480. $owner = $share->getShareOwner();
  481. $currentServer = $this->addressHandler->generateRemoteURL();
  482. if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
  483. throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
  484. }
  485. } catch (\Exception $e) {
  486. throw new ProviderCouldNotAddShareException($e->getMessage());
  487. }
  488. $this->verifyShare($share, $token);
  489. // check if re-sharing is allowed
  490. if ($share->getPermissions() & Constants::PERMISSION_SHARE) {
  491. // the recipient of the initial share is now the initiator for the re-share
  492. $share->setSharedBy($share->getSharedWith());
  493. $share->setSharedWith($shareWith);
  494. $result = $this->federatedShareProvider->create($share);
  495. $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
  496. return ['token' => $result->getToken(), 'providerId' => $result->getId()];
  497. } else {
  498. throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
  499. }
  500. }
  501. /**
  502. * update permission of a re-share so that the share dialog shows the right
  503. * permission if the owner or the sender changes the permission
  504. *
  505. * @param string $id
  506. * @param array $notification
  507. * @return array<string>
  508. * @throws AuthenticationFailedException
  509. * @throws BadRequestException
  510. */
  511. protected function updateResharePermissions($id, array $notification) {
  512. throw new HintException('Updating reshares not allowed');
  513. }
  514. /**
  515. * translate OCM Permissions to Nextcloud permissions
  516. *
  517. * @param array $ocmPermissions
  518. * @return int
  519. * @throws BadRequestException
  520. */
  521. protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
  522. $ncPermissions = 0;
  523. foreach ($ocmPermissions as $permission) {
  524. switch (strtolower($permission)) {
  525. case 'read':
  526. $ncPermissions += Constants::PERMISSION_READ;
  527. break;
  528. case 'write':
  529. $ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
  530. break;
  531. case 'share':
  532. $ncPermissions += Constants::PERMISSION_SHARE;
  533. break;
  534. default:
  535. throw new BadRequestException(['permission']);
  536. }
  537. }
  538. return $ncPermissions;
  539. }
  540. /**
  541. * update permissions in database
  542. *
  543. * @param IShare $share
  544. * @param int $permissions
  545. */
  546. protected function updatePermissionsInDatabase(IShare $share, $permissions) {
  547. $query = $this->connection->getQueryBuilder();
  548. $query->update('share')
  549. ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
  550. ->set('permissions', $query->createNamedParameter($permissions))
  551. ->executeStatement();
  552. }
  553. /**
  554. * get file
  555. *
  556. * @param string $user
  557. * @param int $fileSource
  558. * @return array with internal path of the file and a absolute link to it
  559. */
  560. private function getFile($user, $fileSource) {
  561. \OC_Util::setupFS($user);
  562. try {
  563. $file = Filesystem::getPath($fileSource);
  564. } catch (NotFoundException $e) {
  565. $file = null;
  566. }
  567. $args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file];
  568. $link = Util::linkToAbsolute('files', 'index.php', $args);
  569. return [$file, $link];
  570. }
  571. /**
  572. * check if we are the initiator or the owner of a re-share and return the correct UID
  573. *
  574. * @param IShare $share
  575. * @return string
  576. */
  577. protected function getCorrectUid(IShare $share) {
  578. if ($this->userManager->userExists($share->getShareOwner())) {
  579. return $share->getShareOwner();
  580. }
  581. return $share->getSharedBy();
  582. }
  583. /**
  584. * check if we got the right share
  585. *
  586. * @param IShare $share
  587. * @param string $token
  588. * @return bool
  589. * @throws AuthenticationFailedException
  590. */
  591. protected function verifyShare(IShare $share, $token) {
  592. if (
  593. $share->getShareType() === IShare::TYPE_REMOTE &&
  594. $share->getToken() === $token
  595. ) {
  596. return true;
  597. }
  598. if ($share->getShareType() === IShare::TYPE_CIRCLE) {
  599. try {
  600. $knownShare = $this->shareManager->getShareByToken($token);
  601. if ($knownShare->getId() === $share->getId()) {
  602. return true;
  603. }
  604. } catch (ShareNotFound $e) {
  605. }
  606. }
  607. throw new AuthenticationFailedException();
  608. }
  609. /**
  610. * check if server-to-server sharing is enabled
  611. *
  612. * @param bool $incoming
  613. * @return bool
  614. */
  615. private function isS2SEnabled($incoming = false) {
  616. $result = $this->appManager->isEnabledForUser('files_sharing');
  617. if ($incoming) {
  618. $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
  619. } else {
  620. $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
  621. }
  622. return $result;
  623. }
  624. /**
  625. * get the supported share types, e.g. "user", "group", etc.
  626. *
  627. * @return array
  628. *
  629. * @since 14.0.0
  630. */
  631. public function getSupportedShareTypes() {
  632. return ['user', 'group'];
  633. }
  634. public function getUserDisplayName(string $userId): string {
  635. // check if gss is enabled and available
  636. if (!$this->appManager->isInstalled('globalsiteselector')
  637. || !class_exists('\OCA\GlobalSiteSelector\Service\SlaveService')) {
  638. return '';
  639. }
  640. try {
  641. $slaveService = Server::get(SlaveService::class);
  642. } catch (\Throwable $e) {
  643. Server::get(LoggerInterface::class)->error(
  644. $e->getMessage(),
  645. ['exception' => $e]
  646. );
  647. return '';
  648. }
  649. return $slaveService->getUserDisplayName($this->cloudIdManager->removeProtocolFromUrl($userId), false);
  650. }
  651. }