diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 23f521a51c..655c01cf85 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -33,6 +33,7 @@ use OCA\FederatedFileSharing\Controller\RequestHandlerController; use OCA\FederatedFileSharing\FederatedShareProvider; use OCA\FederatedFileSharing\Notifications; use OCA\FederatedFileSharing\OCM\CloudFederationProvider; +use OCA\FederatedFileSharing\OCM\CloudFederationProviderFiles; use OCP\AppFramework\App; use OCP\GlobalScale\IConfig; @@ -51,7 +52,18 @@ class Application extends App { $cloudFederationManager->addCloudFederationProvider('file', 'Federated Files Sharing', function() use ($container) { - return new CloudFederationProvider('file'); + $server = $container->getServer(); + return new CloudFederationProviderFiles( + $server->getAppManager(), + $server->query(FederatedShareProvider::class), + $server->query(AddressHandler::class), + $server->getLogger(), + $server->getUserManager(), + $server->getCloudIdManager(), + $server->getActivityManager(), + $server->getNotificationManager(), + $server->getURLGenerator() + ); }); $container->registerService('RequestHandlerController', function(SimpleContainer $c) use ($server) { @@ -76,7 +88,9 @@ class Application extends App { $addressHandler, $server->getUserManager(), $server->getCloudIdManager(), - $server->getLogger() + $server->getLogger(), + $server->getCloudFederationFactory(), + $server->getCloudFederationProviderManager() ); }); } diff --git a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php index 422f12dda2..2d0a3c528f 100644 --- a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php +++ b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php @@ -40,6 +40,10 @@ use OCP\AppFramework\OCS\OCSForbiddenException; use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\AppFramework\OCSController; use OCP\Constants; +use OCP\Federation\Exceptions\ProviderCouldNotAddShareException; +use OCP\Federation\Exceptions\ProviderDoesNotExistsException; +use OCP\Federation\ICloudFederationFactory; +use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudIdManager; use OCP\Files\NotFoundException; use OCP\IDBConnection; @@ -78,6 +82,12 @@ class RequestHandlerController extends OCSController { /** @var ILogger */ private $logger; + /** @var ICloudFederationFactory */ + private $cloudFederationFactory; + + /** @var ICloudFederationProviderManager */ + private $cloudFederationProviderManager; + /** * Server2Server constructor. * @@ -90,6 +100,9 @@ class RequestHandlerController extends OCSController { * @param AddressHandler $addressHandler * @param IUserManager $userManager * @param ICloudIdManager $cloudIdManager + * @param ILogger $logger + * @param ICloudFederationFactory $cloudFederationFactory + * @param ICloudFederationProviderManager $cloudFederationProviderManager */ public function __construct($appName, IRequest $request, @@ -100,7 +113,9 @@ class RequestHandlerController extends OCSController { AddressHandler $addressHandler, IUserManager $userManager, ICloudIdManager $cloudIdManager, - ILogger $logger + ILogger $logger, + ICloudFederationFactory $cloudFederationFactory, + ICloudFederationProviderManager $cloudFederationProviderManager ) { parent::__construct($appName, $request); @@ -112,6 +127,8 @@ class RequestHandlerController extends OCSController { $this->userManager = $userManager; $this->cloudIdManager = $cloudIdManager; $this->logger = $logger; + $this->cloudFederationFactory = $cloudFederationFactory; + $this->cloudFederationProviderManager = $cloudFederationProviderManager; } /** @@ -125,10 +142,6 @@ class RequestHandlerController extends OCSController { */ public function createShare() { - if (!$this->isS2SEnabled(true)) { - throw new OCSException('Server does not support federated cloud sharing', 503); - } - $remote = isset($_POST['remote']) ? $_POST['remote'] : null; $token = isset($_POST['token']) ? $_POST['token'] : null; $name = isset($_POST['name']) ? $_POST['name'] : null; @@ -139,92 +152,41 @@ class RequestHandlerController extends OCSController { $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null; $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null; - if ($remote && $token && $name && $owner && $remoteId && $shareWith) { - - if (!\OCP\Util::isValidFileName($name)) { - throw new OCSException('The mountpoint name contains invalid characters.', 400); - } - - // 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 (!\OC::$server->getUserManager()->userExists($shareWith)) { - throw new OCSException('User does not exists', 400); - } - - \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), - $shareWith - ); - - try { - $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); - $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); - - if ($ownerFederatedId === null) { - $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId(); - } - // if the owner of the share and the initiator are the same user - // we also complete the federated share ID for the initiator - if ($sharedByFederatedId === null && $owner === $sharedBy) { - $sharedByFederatedId = $ownerFederatedId; - } - - $event = \OC::$server->getActivityManager()->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); - - $urlGenerator = \OC::$server->getURLGenerator(); - - $notificationManager = \OC::$server->getNotificationManager(); - $notification = $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($urlGenerator->getAbsoluteURL($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($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); - $notification->addAction($acceptAction); - - $notificationManager->notify($notification); - - return new Http\DataResponse(); - } catch (\Exception $e) { - $this->logger->logException($e, [ - 'message' => 'Server can not add remote share.', - 'level' => ILogger::ERROR, - 'app' => 'files_sharing' - ]); - throw new OCSException('internal server error, was not able to add share from ' . $remote, 500); - } + if ($ownerFederatedId === null) { + $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId(); + } + // if the owner of the share and the initiator are the same user + // we also complete the federated share ID for the initiator + if ($sharedByFederatedId === null && $owner === $sharedBy) { + $sharedByFederatedId = $ownerFederatedId; } - throw new OCSException('server can not add remote share, missing parameter', 400); + $share = $this->cloudFederationFactory->getCloudFederationShare( + $shareWith, + $name, + '', + $remoteId, + $ownerFederatedId, + $owner, + $sharedByFederatedId, + $sharedBy, + ['name' => 'webdav', 'options' => ['access_token' => $token]], + 'user', + 'file' + ); + + try { + $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file'); + $provider->shareReceived($share); + } catch (ProviderDoesNotExistsException $e) { + throw new OCSException('Server does not support federated cloud sharing', 503); + } catch (ProviderCouldNotAddShareException $e) { + throw new OCSException($e->getMessage(), $e->getCode()); + } catch (\Exception $e) { + throw new OCSException('internal server error, was not able to add share from ' . $remote, 500); + } + + return new Http\DataResponse(); } /** diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index d2962d9c59..ecc1e1710b 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -30,7 +30,6 @@ namespace OCA\FederatedFileSharing; use OC\Share20\Share; -use OCA\FederatedFileSharing\OCM\CloudFederationProvider; use OCP\Federation\ICloudIdManager; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\Folder; @@ -92,9 +91,6 @@ class FederatedShareProvider implements IShareProvider { /** @var \OCP\GlobalScale\IConfig */ private $gsConfig; - /** @var CloudFederationProvider */ - private $cloudFederationProvider; - /** * DefaultShareProvider constructor. * @@ -109,7 +105,6 @@ class FederatedShareProvider implements IShareProvider { * @param IUserManager $userManager * @param ICloudIdManager $cloudIdManager * @param \OCP\GlobalScale\IConfig $globalScaleConfig - * @param CloudFederationProvider $cloudFederationProvider */ public function __construct( IDBConnection $connection, @@ -122,8 +117,7 @@ class FederatedShareProvider implements IShareProvider { IConfig $config, IUserManager $userManager, ICloudIdManager $cloudIdManager, - \OCP\GlobalScale\IConfig $globalScaleConfig, - CloudFederationProvider $cloudFederationProvider + \OCP\GlobalScale\IConfig $globalScaleConfig ) { $this->dbConnection = $connection; $this->addressHandler = $addressHandler; @@ -136,8 +130,6 @@ class FederatedShareProvider implements IShareProvider { $this->userManager = $userManager; $this->cloudIdManager = $cloudIdManager; $this->gsConfig = $globalScaleConfig; - $this->cloudFederationProvider = $cloudFederationProvider; - } /** diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProvider.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProvider.php deleted file mode 100644 index 36b2d282b9..0000000000 --- a/apps/federatedfilesharing/lib/ocm/CloudFederationProvider.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * @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 OCP\Federation\ICloudFederationFactory; -use OCP\Federation\ICloudFederationProvider; -use OCP\Federation\ICloudFederationShare; - -class CloudFederationProvider implements ICloudFederationProvider { - - /** @var string */ - private $shareType; - - /** - * CloudFederationProvider constructor. - * - * @param string $shareType - */ - public function __construct($shareType) { - $this->shareType = $shareType; - } - - /** - * @return string - */ - public function getShareType() { - return $this->shareType; - } - - /** - * send new share to another server - * - * @since 14.0.0 - */ - public function sendShare() { - // TODO: Implement sendShare() method. - } - - /** - * share received from another server - * - * @param ICloudFederationShare $share - * @return string provider specific unique ID of the share - * - * @since 14.0.0 - */ - public function shareReceived(ICloudFederationShare $share) { - // TODO: Implement shareReceived() method. - } - - /** - * notification received from another server - * - * @param string $id unique ID of a already existing share - * @param array $notification provider specific notification - * - * @throws \OCP\Federation\Exceptions\ShareNotFoundException - * - * @since 14.0.0 - */ - public function notificationReceived($id, $notification) { - // TODO: Implement notificationReceived() method. - } -} diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php new file mode 100644 index 0000000000..f05f446914 --- /dev/null +++ b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php @@ -0,0 +1,272 @@ + + * + * @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\ProviderCouldNotAddShareException; +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'; + } + + /** + * send new share to another server + * + * @since 14.0.0 + */ + public function sendShare() { + // TODO: Implement sendShare() method. + } + + /** + * 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 = isset($protocol['options']['access_token']) ? $protocol['options']['access_token'] : null; + $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), + $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 $id unique ID of a already existing share + * @param array $notification provider specific notification + * + * @throws \OCP\Federation\Exceptions\ShareNotFoundException + * + * @since 14.0.0 + */ + public function notificationReceived($id, $notification) { + // TODO: Implement notificationReceived() method. + } + + /** + * 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; + } + + +} diff --git a/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php b/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php index b608437aa3..205206d5af 100644 --- a/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php +++ b/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php @@ -22,7 +22,13 @@ namespace OCP\Federation\Exceptions; use OC\HintException; +use OCP\AppFramework\Http; class ProviderCouldNotAddShareException extends HintException { + public function __construct($message, $hint = '', $code = Http::STATUS_BAD_REQUEST, \Exception $previous = null) { + parent::__construct($message, $hint, $code, $previous); + } + + } diff --git a/lib/public/Federation/ICloudFederationProvider.php b/lib/public/Federation/ICloudFederationProvider.php index 4c11fc2039..535f61aae8 100644 --- a/lib/public/Federation/ICloudFederationProvider.php +++ b/lib/public/Federation/ICloudFederationProvider.php @@ -21,6 +21,7 @@ namespace OCP\Federation; +use OCP\Federation\Exceptions\ProviderCouldNotAddShareException; use OCP\Federation\Exceptions\ShareNotFoundException; /** @@ -35,17 +36,12 @@ use OCP\Federation\Exceptions\ShareNotFoundException; interface ICloudFederationProvider { - /** - * ICloudFederationProvider constructor. - * - * @param $shareType define the share type, handled by this provider - */ - public function __construct($shareType); - /** * get the name of the share type, handled by this provider * * @return string + * + * @since 14.0.0 */ public function getShareType(); @@ -62,6 +58,8 @@ interface ICloudFederationProvider { * @param ICloudFederationShare $share * @return string provider specific unique ID of the share * + * @throws ProviderCouldNotAddShareException + * * @since 14.0.0 */ public function shareReceived(ICloudFederationShare $share);