diff options
11 files changed, 185 insertions, 35 deletions
diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php index d551f464c22..4f16c369a2f 100644 --- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php +++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php @@ -32,6 +32,7 @@ use OCP\Federation\Exceptions\ShareNotFoundException; use OCP\Federation\ICloudFederationFactory; use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\Exceptions\ProviderDoesNotExistsException; +use OCP\Federation\ICloudIdManager; use OCP\ILogger; use OCP\IRequest; use OCP\IURLGenerator; @@ -65,6 +66,9 @@ class RequestHandlerController extends Controller { /** @var ICloudFederationFactory */ private $factory; + /** @var ICloudIdManager */ + private $cloudIdManager; + public function __construct($appName, IRequest $request, ILogger $logger, @@ -72,7 +76,8 @@ class RequestHandlerController extends Controller { IURLGenerator $urlGenerator, ICloudFederationProviderManager $cloudFederationProviderManager, Config $config, - ICloudFederationFactory $factory + ICloudFederationFactory $factory, + ICloudIdManager $cloudIdManager ) { parent::__construct($appName, $request); @@ -82,6 +87,7 @@ class RequestHandlerController extends Controller { $this->cloudFederationProviderManager = $cloudFederationProviderManager; $this->config = $config; $this->factory = $factory; + $this->cloudIdManager = $cloudIdManager; } /** @@ -104,7 +110,7 @@ class RequestHandlerController extends Controller { * @param $resourceType ('file', 'calendar',...) * @return Http\DataResponse|JSONResponse * - * Example: curl -H "Content-Type: application/json" -X POST -d '{"shareWith":"admin1","name":"welcome server2.txt","description":"desc","providerId":"2","owner":"admin2@http://localhost/server2","ownerDisplayName":"admin2 display","shareType":"user","resourceType":"file","protocol":{"name":"webdav","options":{"access_token":"8Lrd1FVEREthux7","permissions":31}}}' http://localhost/server/index.php/ocm/shares + * Example: curl -H "Content-Type: application/json" -X POST -d '{"shareWith":"admin1@serve1","name":"welcome server2.txt","description":"desc","providerId":"2","owner":"admin2@http://localhost/server2","ownerDisplayName":"admin2 display","shareType":"user","resourceType":"file","protocol":{"name":"webdav","options":{"access_token":"8Lrd1FVEREthux7","permissions":31}}}' http://localhost/server/index.php/ocm/shares */ public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) { @@ -133,7 +139,9 @@ class RequestHandlerController extends Controller { ); } - $shareWith = $this->mapUid($shareWith); + $cloudId = $this->cloudIdManager->resolveCloudId($shareWith); + $shareWithLocalId = $cloudId->getUser(); + $shareWith = $this->mapUid($shareWithLocalId); if (!$this->userManager->userExists($shareWith)) { return new JSONResponse( diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 655c01cf85d..0b61e0a0b0d 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -76,7 +76,9 @@ class Application extends App { $addressHandler, $server->getHTTPClientService(), $server->query(\OCP\OCS\IDiscoveryService::class), - \OC::$server->getJobList() + \OC::$server->getJobList(), + \OC::$server->getCloudFederationProviderManager(), + \OC::$server->getCloudFederationFactory() ); return new RequestHandlerController( $c->query('AppName'), @@ -121,7 +123,9 @@ class Application extends App { $addressHandler, \OC::$server->getHTTPClientService(), \OC::$server->query(\OCP\OCS\IDiscoveryService::class), - \OC::$server->getJobList() + \OC::$server->getJobList(), + \OC::$server->getCloudFederationProviderManager(), + \OC::$server->getCloudFederationFactory() ); $tokenHandler = new \OCA\FederatedFileSharing\TokenHandler( \OC::$server->getSecureRandom() diff --git a/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php index de2edfe60f7..e3d7028ef65 100644 --- a/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php +++ b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php @@ -75,7 +75,9 @@ class RetryJob extends Job { $addressHandler, \OC::$server->getHTTPClientService(), \OC::$server->query(\OCP\OCS\IDiscoveryService::class), - \OC::$server->getJobList() + \OC::$server->getJobList(), + \OC::$server->getCloudFederationProviderManager(), + \OC::$server->getCloudFederationFactory() ); } diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index 6f3f699e5c4..65151e34135 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -27,6 +27,8 @@ namespace OCA\FederatedFileSharing; use OCP\AppFramework\Http; use OCP\BackgroundJob\IJobList; +use OCP\Federation\ICloudFederationFactory; +use OCP\Federation\ICloudFederationProviderManager; use OCP\Http\Client\IClientService; use OCP\OCS\IDiscoveryService; @@ -45,22 +47,34 @@ class Notifications { /** @var IJobList */ private $jobList; + /** @var ICloudFederationProviderManager */ + private $federationProviderManager; + + /** @var ICloudFederationFactory */ + private $cloudFederationFactory; + /** * @param AddressHandler $addressHandler * @param IClientService $httpClientService * @param IDiscoveryService $discoveryService * @param IJobList $jobList + * @param ICloudFederationProviderManager $federationProviderManager + * @param ICloudFederationFactory $cloudFederationFactory */ public function __construct( AddressHandler $addressHandler, IClientService $httpClientService, IDiscoveryService $discoveryService, - IJobList $jobList + IJobList $jobList, + ICloudFederationProviderManager $federationProviderManager, + ICloudFederationFactory $cloudFederationFactory ) { $this->addressHandler = $addressHandler; $this->httpClientService = $httpClientService; $this->discoveryService = $discoveryService; $this->jobList = $jobList; + $this->federationProviderManager = $federationProviderManager; + $this->cloudFederationFactory = $cloudFederationFactory; } /** @@ -100,7 +114,10 @@ class Notifications { $result = $this->tryHttpPostToShareEndpoint($remote, '', $fields); $status = json_decode($result['result'], true); - if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) { + $ocsStatus = isset($status['ocs']); + $ocsSuccess = $ocsStatus && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200); + + if ($result['success'] && (!$ocsStatus ||$ocsSuccess)) { \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]); return true; } @@ -271,11 +288,11 @@ class Notifications { * @param string $remoteDomain * @param string $urlSuffix * @param array $fields post parameters + * @param string $action define the action (possible values: share, reshare, accept, decline, unshare, revoke, permissions) * @return array * @throws \Exception */ - protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) { - $client = $this->httpClientService->newClient(); + protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields, $action="share") { if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) { $remoteDomain = 'https://' . $remoteDomain; @@ -286,6 +303,15 @@ class Notifications { 'result' => '', ]; + // if possible we use the new OCM API + $ocmResult = $this->tryOCMEndPoint($remoteDomain, $fields, $action); + if ($ocmResult) { + $result['success'] = true; + return $result; + } + + // Fall back to old API + $client = $this->httpClientService->newClient(); $federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING'); $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares'; try { @@ -307,4 +333,58 @@ class Notifications { return $result; } + + /** + * check if server supports the new OCM api and ask for the correct end-point + * + * @param string $url + * @return string + */ + protected function getOCMEndPoint($url) { + $client = $this->httpClientService->newClient(); + try { + $response = $client->get($url, ['timeout' => 10, 'connect_timeout' => 10]); + } catch (\Exception $e) { + return ''; + } + + $result = $response->getBody(); + $result = json_decode($result, true); + + if (isset($result['end-point'])) { + return $result['end-point']; + } + + return ''; + } + + /** + * send action regarding federated sharing to the remote server using the OCM API + * + * @param $remoteDomain + * @param $fields + * @param $action + * + * @return bool + */ + protected function tryOCMEndPoint($remoteDomain, $fields, $action) { + switch ($action) { + case 'share': + $share = $this->cloudFederationFactory->getCloudFederationShare( + $fields['shareWith'] . '@' . $remoteDomain, + $fields['name'], + '', + $fields['remoteId'], + $fields['ownerFederatedId'], + $fields['owner'], + $fields['sharedByFederatedId'], + $fields['sharedBy'], + ['name' => 'webdav', 'options' => ['access_token' => $fields['token'], 'permissions' => ['read', 'write', 'share']]], + 'user', + 'file' + ); + return $this->federationProviderManager->sendShare($share); + } + + } } diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php index f05f4469148..dea4c3f5fc1 100644 --- a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php @@ -109,15 +109,6 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } /** - * 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 @@ -186,6 +177,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { \OC::$server->getHTTPClientService(), \OC::$server->getNotificationManager(), \OC::$server->query(\OCP\OCS\IDiscoveryService::class), + \OC::$server->getCloudFederationProviderManager(), $shareWith ); diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php index 73e1dd99c61..dcf666ca266 100644 --- a/lib/private/Federation/CloudFederationProviderManager.php +++ b/lib/private/Federation/CloudFederationProviderManager.php @@ -29,6 +29,8 @@ use OCP\Federation\ICloudFederationNotification; use OCP\Federation\ICloudFederationProvider; use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationShare; +use OCP\Federation\ICloudIdManager; +use OCP\Http\Client\IClientService; /** * Class Manager @@ -45,9 +47,26 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager /** @var IAppManager */ private $appManager; - public function __construct(IAppManager $appManager) { + /** @var IClientService */ + private $httpClientService; + + /** @var ICloudIdManager */ + private $cloudIdManager; + + /** + * CloudFederationProviderManager constructor. + * + * @param IAppManager $appManager + * @param IClientService $httpClientService + * @param ICloudIdManager $cloudIdManager + */ + public function __construct(IAppManager $appManager, + IClientService $httpClientService, + ICloudIdManager $cloudIdManager) { $this->cloudFederationProvider= []; $this->appManager = $appManager; + $this->httpClientService = $httpClientService; + $this->cloudIdManager = $cloudIdManager; } @@ -103,7 +122,32 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager } public function sendShare(ICloudFederationShare $share) { - // TODO: Implement sendShare() method. + $ocmEndPoint = $this->getOCMEndPoint($share->getShareWith()); + + if (empty($ocmEndPoint)) { + return false; + } + + $client = $this->httpClientService->newClient(); + try { + $response = $client->post($ocmEndPoint . '/shares', [ + 'body' => $share->getShare(), + 'timeout' => 10, + 'connect_timeout' => 10, + ]); + $result['result'] = $response->getBody(); + $result['success'] = 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. + // (flat re-shares has been introduced in Nextcloud 9.1) + if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) { + throw $e; + } + } + + return true; + } public function sendNotification(ICloudFederationNotification $notification) { @@ -118,5 +162,30 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager public function isReady() { return $this->appManager->isEnabledForUser('cloud_federation_api', false); } + /** + * check if server supports the new OCM api and ask for the correct end-point + * + * @param string $recipient full federated cloud ID of the recipient of a share + * @return string + */ + protected function getOCMEndPoint($recipient) { + $cloudId = $this->cloudIdManager->resolveCloudId($recipient); + $client = $this->httpClientService->newClient(); + try { + $response = $client->get($cloudId->getRemote() . '/ocm-provider/', ['timeout' => 10, 'connect_timeout' => 10]); + } catch (\Exception $e) { + return ''; + } + + $result = $response->getBody(); + $result = json_decode($result, true); + + if (isset($result['end-point'])) { + return $result['end-point']; + } + + return ''; + } + } diff --git a/lib/private/Federation/CloudFederationShare.php b/lib/private/Federation/CloudFederationShare.php index 4622dc096d7..5bc172ab6b6 100644 --- a/lib/private/Federation/CloudFederationShare.php +++ b/lib/private/Federation/CloudFederationShare.php @@ -203,14 +203,14 @@ class CloudFederationShare implements ICloudFederationShare { } /** - * get JSON encoded share, ready to send out + * get the whole share, ready to send out * - * @return string + * @return array * * @since 14.0.0 */ public function getShare() { - return json_encode($this->share); + return $this->share; } /** diff --git a/lib/private/Server.php b/lib/private/Server.php index 7156c8a2c22..8f1b24eb11d 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()); + return new CloudFederationProviderManager($c->getAppManager(), $c->getHTTPClientService(), $c->getCloudIdManager()); }); $this->registerService(ICloudFederationFactory::class, function (Server $c) { diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index 456b6dbc596..7d866db24fa 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -116,7 +116,9 @@ class ProviderFactory implements IProviderFactory { $addressHandler, $this->serverContainer->getHTTPClientService(), $this->serverContainer->query(\OCP\OCS\IDiscoveryService::class), - $this->serverContainer->getJobList() + $this->serverContainer->getJobList(), + \OC::$server->getCloudFederationProviderManager(), + \OC::$server->getCloudFederationFactory() ); $tokenHandler = new TokenHandler( $this->serverContainer->getSecureRandom() diff --git a/lib/public/Federation/ICloudFederationProvider.php b/lib/public/Federation/ICloudFederationProvider.php index 535f61aae89..38a551000f0 100644 --- a/lib/public/Federation/ICloudFederationProvider.php +++ b/lib/public/Federation/ICloudFederationProvider.php @@ -46,13 +46,6 @@ interface ICloudFederationProvider { public function getShareType(); /** - * send new share to another server - * - * @since 14.0.0 - */ - public function sendShare(); - - /** * share received from another server * * @param ICloudFederationShare $share diff --git a/lib/public/Federation/ICloudFederationShare.php b/lib/public/Federation/ICloudFederationShare.php index b116da0fb54..ce5065c70b8 100644 --- a/lib/public/Federation/ICloudFederationShare.php +++ b/lib/public/Federation/ICloudFederationShare.php @@ -123,9 +123,9 @@ interface ICloudFederationShare { public function setShareType($shareType); /** - * get JSON encoded share, ready to send out + * get the whole share, ready to send out * - * @return string + * @return array * * @since 14.0.0 */ |