From db428ea5471a5be5517911b3bf2f3a6d3f86e297 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 9 May 2018 17:06:35 +0200 Subject: [PATCH] send accept share notification (WIP) Signed-off-by: Bjoern Schiessle --- .../Controller/RequestHandlerController.php | 23 +++++---- .../lib/ocm/CloudFederationProviderFiles.php | 20 ++++++-- .../files_sharing/lib/AppInfo/Application.php | 2 + apps/files_sharing/lib/External/Manager.php | 45 +++++++++++++++++ apps/files_sharing/lib/Hooks.php | 2 + .../CloudFederationNotification.php | 19 ++++--- .../CloudFederationProviderManager.php | 50 ++++++++++++++++--- lib/private/Server.php | 2 +- .../ActionNotSupportedException.php | 39 +++++++++++++++ .../ICloudFederationNotification.php | 9 ++-- .../Federation/ICloudFederationProvider.php | 8 +-- .../ICloudFederationProviderManager.php | 5 +- 12 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 lib/public/Federation/Exceptions/ActionNotSupportedException.php diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php index 4f16c369a2..319380ec3c 100644 --- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php +++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php @@ -27,6 +27,7 @@ use OCA\CloudFederationAPI\Config; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; +use OCP\Federation\Exceptions\ActionNotSupportedException; use OCP\Federation\Exceptions\ProviderCouldNotAddShareException; use OCP\Federation\Exceptions\ShareNotFoundException; use OCP\Federation\ICloudFederationFactory; @@ -190,13 +191,12 @@ class RequestHandlerController extends Controller { /** * receive notification about existing share * - * @param $resourceType ('file', 'calendar',...) - * @param string $name resource name (e.g "file", "calendar",...) - * @param string $id unique id of the corresponding item on the receiving site - * @param array $notification contain the actual notification, content is defined by cloud federation provider + * @param string $notificationType (notification type, e.g. SHARE_ACCEPTED) + * @param string $resourceType (calendar, file, contact,...) + * @param array $message contain the actual notification, content is defined by cloud federation provider * @return JSONResponse */ - public function receiveNotification($resourceType, $name, $id, $notification) { + public function receiveNotification($notificationType, $resourceType, $message) { if (!$this->config->incomingRequestsEnabled()) { return new JSONResponse( ['message' => 'This server doesn\'t support outgoing federated shares'], @@ -205,9 +205,9 @@ class RequestHandlerController extends Controller { } // check if all required parameters are set - if ($name === null || - $id === null || - !is_array($notification) + if ($notificationType === null || + $resourceType === null || + !is_array($message) ) { return new JSONResponse( ['message' => 'Missing arguments'], @@ -217,7 +217,7 @@ class RequestHandlerController extends Controller { try { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType); - $provider->notificationReceived($id, $notification); + $provider->notificationReceived($notificationType, $message); } catch (ProviderDoesNotExistsException $e) { return new JSONResponse( ['message' => $e->getMessage()], @@ -228,6 +228,11 @@ class RequestHandlerController extends Controller { ['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST ); + } catch (ActionNotSupportedException $e) { + return new JSONResponse( + ['message' => $e->getMessage()], + Http::STATUS_NOT_IMPLEMENTED + ); } catch (\Exception $e) { return new JSONResponse( ['message' => 'Internal error at ' . $this->urlGenerator->getBaseUrl()], diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php index dea4c3f5fc..6c5b63b1cd 100644 --- a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php @@ -27,7 +27,9 @@ 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; @@ -178,6 +180,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { \OC::$server->getNotificationManager(), \OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getCloudFederationProviderManager(), + \OC::$server->getCloudFederationFactory(), $shareWith ); @@ -230,15 +233,22 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { /** * notification received from another server * - * @param string $id unique ID of a already existing share - * @param array $notification provider specific notification + * @param string $notificationType (e.g. SHARE_ACCEPTED) + * @param array $message * - * @throws \OCP\Federation\Exceptions\ShareNotFoundException + * @throws ShareNotFoundException + * @throws ActionNotSupportedException * * @since 14.0.0 */ - public function notificationReceived($id, $notification) { - // TODO: Implement notificationReceived() method. + public function notificationReceived($notificationType, array $message) { + switch ($notificationType) { + case 'SHARE_ACCEPTED' : + return; + } + + + throw new ActionNotSupportedException($notificationType); } /** diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index e0c40730b3..e6ab4eb2cf 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -103,6 +103,8 @@ class Application extends App { $server->getHTTPClientService(), $server->getNotificationManager(), $server->query(\OCP\OCS\IDiscoveryService::class), + $server->getCloudFederationProviderManager(), + $server->getCloudFederationFactory(), $uid ); }); diff --git a/apps/files_sharing/lib/External/Manager.php b/apps/files_sharing/lib/External/Manager.php index c9303ac224..cb1e947f60 100644 --- a/apps/files_sharing/lib/External/Manager.php +++ b/apps/files_sharing/lib/External/Manager.php @@ -33,6 +33,8 @@ namespace OCA\Files_Sharing\External; use OC\Files\Filesystem; use OCA\Files_Sharing\Helper; +use OCP\Federation\ICloudFederationFactory; +use OCP\Federation\ICloudFederationProviderManager; use OCP\Files; use OCP\Files\Storage\IStorageFactory; use OCP\Http\Client\IClientService; @@ -79,6 +81,12 @@ class Manager { */ private $discoveryService; + /** @var ICloudFederationProviderManager */ + private $cloudFederationProviderManager; + + /** @var ICloudFederationFactory */ + private $cloudFederationFactory; + /** * @param IDBConnection $connection * @param \OC\Files\Mount\Manager $mountManager @@ -86,6 +94,8 @@ class Manager { * @param IClientService $clientService * @param IManager $notificationManager * @param IDiscoveryService $discoveryService + * @param ICloudFederationProviderManager $cloudFederationProviderManager + * @param ICloudFederationFactory $cloudFederationFactory * @param string $uid */ public function __construct(IDBConnection $connection, @@ -94,6 +104,8 @@ class Manager { IClientService $clientService, IManager $notificationManager, IDiscoveryService $discoveryService, + ICloudFederationProviderManager $cloudFederationProviderManager, + ICloudFederationFactory $cloudFederationFactory, $uid) { $this->connection = $connection; $this->mountManager = $mountManager; @@ -102,6 +114,8 @@ class Manager { $this->uid = $uid; $this->notificationManager = $notificationManager; $this->discoveryService = $discoveryService; + $this->cloudFederationProviderManager = $cloudFederationProviderManager; + $this->cloudFederationFactory = $cloudFederationFactory; } /** @@ -274,6 +288,12 @@ class Manager { */ private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) { + $result = $this->tryOCMEndPoint($remote, $token, $remoteId, $feedback); + + if($result === true) { + return true; + } + $federationEndpoints = $this->discoveryService->discover($remote, 'FEDERATED_SHARING'); $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares'; @@ -299,6 +319,31 @@ class Manager { return ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200); } + /** + * try send accept message to ocm end-point + * + * @param string $remoteDomain + * @param string $token + * @param $remoteId + * @param string $feedback + * @return mixed + */ + protected function tryOCMEndPoint($remoteDomain, $token, $remoteId, $feedback) { + switch ($feedback) { + case 'accept': + $notification = $this->cloudFederationFactory->getCloudFederationNotification(); + $notification->setMessage('SHARE_ACCEPTED', 'file', + [ + 'id' => $remoteId, + 'access_token' => $token + ] + ); + return $this->cloudFederationProviderManager->sendNotification($remoteDomain, $notification); + } + + } + + /** * remove '/user/files' from the path and trailing slashes * diff --git a/apps/files_sharing/lib/Hooks.php b/apps/files_sharing/lib/Hooks.php index 51511ca6b6..cd66fd7702 100644 --- a/apps/files_sharing/lib/Hooks.php +++ b/apps/files_sharing/lib/Hooks.php @@ -40,6 +40,8 @@ class Hooks { \OC::$server->getHTTPClientService(), \OC::$server->getNotificationManager(), \OC::$server->query(\OCP\OCS\IDiscoveryService::class), + \OC::$server->getCloudFederationProviderManager(), + \OC::$server->getCloudFederationFactory(), $params['uid']); $manager->removeUserShares($params['uid']); diff --git a/lib/private/Federation/CloudFederationNotification.php b/lib/private/Federation/CloudFederationNotification.php index ed87b9b0e5..356c47968f 100644 --- a/lib/private/Federation/CloudFederationNotification.php +++ b/lib/private/Federation/CloudFederationNotification.php @@ -30,23 +30,28 @@ class CloudFederationNotification implements ICloudFederationNotification { /** * add a message to the notification * - * @param string $identifier - * @param string $message + * @param string $notificationType (e.g. SHARE_ACCEPTED) + * @param string $resourceType (e.g. file, calendar, contact,...) + * @param array $message * * @since 14.0.0 */ - public function setMessage($identifier, $message) { - $this->message[$identifier] = $message; + public function setMessage($notificationType, $resourceType, array $message) { + $this->message = [ + 'notificationType' => $notificationType, + 'resourceType' => $resourceType, + 'message' => $message, + ]; } /** - * get JSON encoded Message, ready to send out + * get message, ready to send out * - * @return string + * @return array * * @since 14.0.0 */ public function getMessage() { - return json_encode($this->message); + return $this->message; } } diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php index dcf666ca26..c302659fb6 100644 --- a/lib/private/Federation/CloudFederationProviderManager.php +++ b/lib/private/Federation/CloudFederationProviderManager.php @@ -22,8 +22,8 @@ namespace OC\Federation; +use OC\AppFramework\Http; use OCP\App\IAppManager; -use OCP\Federation\Exceptions\ProviderAlreadyExistsException; use OCP\Federation\Exceptions\ProviderDoesNotExistsException; use OCP\Federation\ICloudFederationNotification; use OCP\Federation\ICloudFederationProvider; @@ -31,6 +31,7 @@ use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudIdManager; use OCP\Http\Client\IClientService; +use OCP\ILogger; /** * Class Manager @@ -53,20 +54,26 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager /** @var ICloudIdManager */ private $cloudIdManager; + /** @var ILogger */ + private $logger; + /** * CloudFederationProviderManager constructor. * * @param IAppManager $appManager * @param IClientService $httpClientService * @param ICloudIdManager $cloudIdManager + * @param ILogger $logger */ public function __construct(IAppManager $appManager, IClientService $httpClientService, - ICloudIdManager $cloudIdManager) { + ICloudIdManager $cloudIdManager, + ILogger $logger) { $this->cloudFederationProvider= []; $this->appManager = $appManager; $this->httpClientService = $httpClientService; $this->cloudIdManager = $cloudIdManager; + $this->logger = $logger; } @@ -135,8 +142,11 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager 'timeout' => 10, 'connect_timeout' => 10, ]); - $result['result'] = $response->getBody(); - $result['success'] = true; + + if ($response->getStatusCode() === Http::STATUS_OK) { + return true; + } + } catch (\Exception $e) { // if flat re-sharing is not supported by the remote server // we re-throw the exception and fall back to the old behaviour. @@ -146,12 +156,38 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager } } - return true; + return false; } - public function sendNotification(ICloudFederationNotification $notification) { - // TODO: Implement sendNotification() method. + /** + * @param string $url + * @param ICloudFederationNotification $notification + * @return bool + */ + public function sendNotification($url, ICloudFederationNotification $notification) { + $ocmEndPoint = $this->getOCMEndPoint($url); + + if (empty($ocmEndPoint)) { + return false; + } + + $client = $this->httpClientService->newClient(); + try { + $response = $client->post($ocmEndPoint . '/notifications', [ + 'body' => $notification->getMessage(), + 'timeout' => 10, + 'connect_timeout' => 10, + ]); + if ($response->getStatusCode() === Http::STATUS_OK) { + return true; + } + } catch (\Exception $e) { + // log the error and return false + $this->logger->error('error while sending notification for federated share: ' . $e->getMessage()); + } + + return false; } /** diff --git a/lib/private/Server.php b/lib/private/Server.php index 8f1b24eb11..90e9e81c10 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1117,7 +1117,7 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerService(ICloudFederationProviderManager::class, function (Server $c) { - return new CloudFederationProviderManager($c->getAppManager(), $c->getHTTPClientService(), $c->getCloudIdManager()); + return new CloudFederationProviderManager($c->getAppManager(), $c->getHTTPClientService(), $c->getCloudIdManager(), $c->getLogger()); }); $this->registerService(ICloudFederationFactory::class, function (Server $c) { diff --git a/lib/public/Federation/Exceptions/ActionNotSupportedException.php b/lib/public/Federation/Exceptions/ActionNotSupportedException.php new file mode 100644 index 0000000000..7e7fe70f48 --- /dev/null +++ b/lib/public/Federation/Exceptions/ActionNotSupportedException.php @@ -0,0 +1,39 @@ + + * + * @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 OCP\Federation\Exceptions; + +use OC\HintException; + +class ActionNotSupportedException extends HintException { + + /** + * ActionNotSupportedException constructor. + * + */ + public function __construct($action) { + $l = \OC::$server->getL10N('federation'); + $message = 'Action "' . $action . '" not supported or implemented.'; + $hint = $l->t('Action "%s" not supported or implemented.', [$action]); + parent::__construct($message, $hint); + } + +} diff --git a/lib/public/Federation/ICloudFederationNotification.php b/lib/public/Federation/ICloudFederationNotification.php index 5db93ef0a8..dcdb5b73bd 100644 --- a/lib/public/Federation/ICloudFederationNotification.php +++ b/lib/public/Federation/ICloudFederationNotification.php @@ -26,15 +26,16 @@ interface ICloudFederationNotification { /** * add a message to the notification * - * @param string $identifier - * @param string $message + * @param string $notificationType (e.g. SHARE_ACCEPTED) + * @param string $resourceType (e.g. file, calendar, contact,...) + * @param array $message * * @since 14.0.0 */ - public function setMessage($identifier, $message); + public function setMessage($notificationType, $resourceType, array $message); /** - * get JSON encoded Message, ready to send out + * get message, ready to send out * * @return string * diff --git a/lib/public/Federation/ICloudFederationProvider.php b/lib/public/Federation/ICloudFederationProvider.php index 38a551000f..0d87d76ee5 100644 --- a/lib/public/Federation/ICloudFederationProvider.php +++ b/lib/public/Federation/ICloudFederationProvider.php @@ -21,6 +21,7 @@ namespace OCP\Federation; +use OCP\Federation\Exceptions\ActionNotSupportedException; use OCP\Federation\Exceptions\ProviderCouldNotAddShareException; use OCP\Federation\Exceptions\ShareNotFoundException; @@ -60,13 +61,14 @@ interface ICloudFederationProvider { /** * notification received from another server * - * @param string $id unique ID of a already existing share - * @param array $notification provider specific notification + * @param string $notificationType (e.g SHARE_ACCEPTED) + * @param array $message provider specific notification * * @throws ShareNotFoundException + * @throws ActionNotSupportedException * * @since 14.0.0 */ - public function notificationReceived($id, $notification); + public function notificationReceived($notificationType, array $message); } diff --git a/lib/public/Federation/ICloudFederationProviderManager.php b/lib/public/Federation/ICloudFederationProviderManager.php index 81558c631f..714c6234b7 100644 --- a/lib/public/Federation/ICloudFederationProviderManager.php +++ b/lib/public/Federation/ICloudFederationProviderManager.php @@ -86,12 +86,13 @@ interface ICloudFederationProviderManager { /** * send notification about existing share * + * @param string $url * @param ICloudFederationNotification $notification - * @return mixed + * @return bool * * @since 14.0.0 */ - public function sendNotification(ICloudFederationNotification $notification); + public function sendNotification($url, ICloudFederationNotification $notification); /** * check if the new cloud federation API is ready to be used