* * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ namespace OCA\FederatedFileSharing\OCM; use OC\AppFramework\Http; use OCA\Files_Sharing\Activity\Providers\RemoteShares; use OCA\FederatedFileSharing\AddressHandler; use OCA\FederatedFileSharing\FederatedShareProvider; use OCP\Activity\IManager as IActivityManager; use OCP\App\IAppManager; use OCP\Federation\Exceptions\ActionNotSupportedException; use OCP\Federation\Exceptions\ProviderCouldNotAddShareException; use OCP\Federation\Exceptions\ShareNotFoundException; use OCP\Federation\ICloudFederationProvider; use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudIdManager; use OCP\ILogger; use OCP\IURLGenerator; use OCP\IUserManager; use OCP\Notification\IManager as INotificationManager; class CloudFederationProviderFiles implements ICloudFederationProvider { /** @var IAppManager */ private $appManager; /** @var FederatedShareProvider */ private $federatedShareProvider; /** @var AddressHandler */ private $addressHandler; /** @var ILogger */ private $logger; /** @var IUserManager */ private $userManager; /** @var ICloudIdManager */ private $cloudIdManager; /** @var IActivityManager */ private $activityManager; /** @var INotificationManager */ private $notificationManager; /** @var IURLGenerator */ private $urlGenerator; /** * CloudFederationProvider constructor. * * @param IAppManager $appManager * @param FederatedShareProvider $federatedShareProvider * @param AddressHandler $addressHandler * @param ILogger $logger * @param IUserManager $userManager * @param ICloudIdManager $cloudIdManager * @param IActivityManager $activityManager * @param INotificationManager $notificationManager * @param IURLGenerator $urlGenerator */ public function __construct(IAppManager $appManager, FederatedShareProvider $federatedShareProvider, AddressHandler $addressHandler, ILogger $logger, IUserManager $userManager, ICloudIdManager $cloudIdManager, IActivityManager $activityManager, INotificationManager $notificationManager, IURLGenerator $urlGenerator ) { $this->appManager = $appManager; $this->federatedShareProvider = $federatedShareProvider; $this->addressHandler = $addressHandler; $this->logger = $logger; $this->userManager = $userManager; $this->cloudIdManager = $cloudIdManager; $this->activityManager = $activityManager; $this->notificationManager = $notificationManager; $this->urlGenerator = $urlGenerator; } /** * @return string */ public function getShareType() { return 'file'; } /** * share received from another server * * @param ICloudFederationShare $share * @return string provider specific unique ID of the share * * @throws ProviderCouldNotAddShareException * @throws \OCP\AppFramework\QueryException * @throws \OC\HintException * @since 14.0.0 */ public function shareReceived(ICloudFederationShare $share) { if (!$this->isS2SEnabled(true)) { throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE); } $protocol = $share->getProtocol(); if ($protocol['name'] !== 'webdav') { throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED); } list($ownerUid, $remote) = $this->addressHandler->splitUserRemote($share->getOwner()); $remote = $remote; $token = $share->getShareSecret(); $name = $share->getResourceName(); $owner = $share->getOwnerDisplayName(); $sharedBy = $share->getSharedByDisplayName(); $shareWith = $share->getShareWith(); $remoteId = $share->getProviderId(); $sharedByFederatedId = $share->getSharedBy(); $ownerFederatedId = $share->getOwner(); // if no explicit information about the person who created the share was send // we assume that the share comes from the owner if ($sharedByFederatedId === null) { $sharedBy = $owner; $sharedByFederatedId = $ownerFederatedId; } if ($remote && $token && $name && $owner && $remoteId && $shareWith) { if (!\OCP\Util::isValidFileName($name)) { throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST); } // FIXME this should be a method in the user management instead $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']); \OCP\Util::emitHook( '\OCA\Files_Sharing\API\Server2Server', 'preLoginNameUsedAsUserName', array('uid' => &$shareWith) ); $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']); if (!$this->userManager->userExists($shareWith)) { throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST); } \OC_Util::setupFS($shareWith); $externalManager = new \OCA\Files_Sharing\External\Manager( \OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPClientService(), \OC::$server->getNotificationManager(), \OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getCloudFederationProviderManager(), \OC::$server->getCloudFederationFactory(), $shareWith ); try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); $event = $this->activityManager->generateEvent(); $event->setApp('files_sharing') ->setType('remote_share') ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) ->setAffectedUser($shareWith) ->setObject('remote_share', (int)$shareId, $name); \OC::$server->getActivityManager()->publish($event); $notification = $this->notificationManager->createNotification(); $notification->setApp('files_sharing') ->setUser($shareWith) ->setDateTime(new \DateTime()) ->setObject('remote_share', $shareId) ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]); $declineAction = $notification->createAction(); $declineAction->setLabel('decline') ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE'); $notification->addAction($declineAction); $acceptAction = $notification->createAction(); $acceptAction->setLabel('accept') ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); $notification->addAction($acceptAction); $this->notificationManager->notify($notification); return $shareId; } catch (\Exception $e) { $this->logger->logException($e, [ 'message' => 'Server can not add remote share.', 'level' => \OCP\Util::ERROR, 'app' => 'files_sharing' ]); throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR); } } throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST); } /** * notification received from another server * * @param string $notificationType (e.g. SHARE_ACCEPTED) * @param string $providerId id of the share * @param array $notification payload of the notification * * @throws ShareNotFoundException * @throws ActionNotSupportedException * * @since 14.0.0 */ public function notificationReceived($notificationType, $providerId, array $notification) { switch ($notificationType) { case 'SHARE_ACCEPTED' : return; } throw new ActionNotSupportedException($notification); } /** * check if server-to-server sharing is enabled * * @param bool $incoming * @return bool */ private function isS2SEnabled($incoming = false) { $result = $this->appManager->isEnabledForUser('files_sharing'); if ($incoming) { $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled(); } else { $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); } return $result; } }