use new API to send a federated share if possible

Signed-off-by: Bjoern Schiessle <bjoern@schiessle.org>
pull/9345/head
Bjoern Schiessle 7 years ago
parent 6208f250e8
commit a3948e8a12
No known key found for this signature in database
GPG Key ID: 2378A753E2BF04F6
  1. 14
      apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
  2. 8
      apps/federatedfilesharing/lib/AppInfo/Application.php
  3. 4
      apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php
  4. 88
      apps/federatedfilesharing/lib/Notifications.php
  5. 10
      apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php
  6. 73
      lib/private/Federation/CloudFederationProviderManager.php
  7. 6
      lib/private/Federation/CloudFederationShare.php
  8. 2
      lib/private/Server.php
  9. 4
      lib/private/Share20/ProviderFactory.php
  10. 7
      lib/public/Federation/ICloudFederationProvider.php
  11. 4
      lib/public/Federation/ICloudFederationShare.php

@ -32,6 +32,7 @@ use OCP\Federation\Exceptions\ShareNotFoundException;
use OCP\Federation\ICloudFederationFactory; use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\Exceptions\ProviderDoesNotExistsException; use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
use OCP\Federation\ICloudIdManager;
use OCP\ILogger; use OCP\ILogger;
use OCP\IRequest; use OCP\IRequest;
use OCP\IURLGenerator; use OCP\IURLGenerator;
@ -65,6 +66,9 @@ class RequestHandlerController extends Controller {
/** @var ICloudFederationFactory */ /** @var ICloudFederationFactory */
private $factory; private $factory;
/** @var ICloudIdManager */
private $cloudIdManager;
public function __construct($appName, public function __construct($appName,
IRequest $request, IRequest $request,
ILogger $logger, ILogger $logger,
@ -72,7 +76,8 @@ class RequestHandlerController extends Controller {
IURLGenerator $urlGenerator, IURLGenerator $urlGenerator,
ICloudFederationProviderManager $cloudFederationProviderManager, ICloudFederationProviderManager $cloudFederationProviderManager,
Config $config, Config $config,
ICloudFederationFactory $factory ICloudFederationFactory $factory,
ICloudIdManager $cloudIdManager
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
@ -82,6 +87,7 @@ class RequestHandlerController extends Controller {
$this->cloudFederationProviderManager = $cloudFederationProviderManager; $this->cloudFederationProviderManager = $cloudFederationProviderManager;
$this->config = $config; $this->config = $config;
$this->factory = $factory; $this->factory = $factory;
$this->cloudIdManager = $cloudIdManager;
} }
/** /**
@ -104,7 +110,7 @@ class RequestHandlerController extends Controller {
* @param $resourceType ('file', 'calendar',...) * @param $resourceType ('file', 'calendar',...)
* @return Http\DataResponse|JSONResponse * @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) { 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)) { if (!$this->userManager->userExists($shareWith)) {
return new JSONResponse( return new JSONResponse(

@ -76,7 +76,9 @@ class Application extends App {
$addressHandler, $addressHandler,
$server->getHTTPClientService(), $server->getHTTPClientService(),
$server->query(\OCP\OCS\IDiscoveryService::class), $server->query(\OCP\OCS\IDiscoveryService::class),
\OC::$server->getJobList() \OC::$server->getJobList(),
\OC::$server->getCloudFederationProviderManager(),
\OC::$server->getCloudFederationFactory()
); );
return new RequestHandlerController( return new RequestHandlerController(
$c->query('AppName'), $c->query('AppName'),
@ -121,7 +123,9 @@ class Application extends App {
$addressHandler, $addressHandler,
\OC::$server->getHTTPClientService(), \OC::$server->getHTTPClientService(),
\OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
\OC::$server->getJobList() \OC::$server->getJobList(),
\OC::$server->getCloudFederationProviderManager(),
\OC::$server->getCloudFederationFactory()
); );
$tokenHandler = new \OCA\FederatedFileSharing\TokenHandler( $tokenHandler = new \OCA\FederatedFileSharing\TokenHandler(
\OC::$server->getSecureRandom() \OC::$server->getSecureRandom()

@ -75,7 +75,9 @@ class RetryJob extends Job {
$addressHandler, $addressHandler,
\OC::$server->getHTTPClientService(), \OC::$server->getHTTPClientService(),
\OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
\OC::$server->getJobList() \OC::$server->getJobList(),
\OC::$server->getCloudFederationProviderManager(),
\OC::$server->getCloudFederationFactory()
); );
} }

@ -27,6 +27,8 @@ namespace OCA\FederatedFileSharing;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\BackgroundJob\IJobList; use OCP\BackgroundJob\IJobList;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\OCS\IDiscoveryService; use OCP\OCS\IDiscoveryService;
@ -45,22 +47,34 @@ class Notifications {
/** @var IJobList */ /** @var IJobList */
private $jobList; private $jobList;
/** @var ICloudFederationProviderManager */
private $federationProviderManager;
/** @var ICloudFederationFactory */
private $cloudFederationFactory;
/** /**
* @param AddressHandler $addressHandler * @param AddressHandler $addressHandler
* @param IClientService $httpClientService * @param IClientService $httpClientService
* @param IDiscoveryService $discoveryService * @param IDiscoveryService $discoveryService
* @param IJobList $jobList * @param IJobList $jobList
* @param ICloudFederationProviderManager $federationProviderManager
* @param ICloudFederationFactory $cloudFederationFactory
*/ */
public function __construct( public function __construct(
AddressHandler $addressHandler, AddressHandler $addressHandler,
IClientService $httpClientService, IClientService $httpClientService,
IDiscoveryService $discoveryService, IDiscoveryService $discoveryService,
IJobList $jobList IJobList $jobList,
ICloudFederationProviderManager $federationProviderManager,
ICloudFederationFactory $cloudFederationFactory
) { ) {
$this->addressHandler = $addressHandler; $this->addressHandler = $addressHandler;
$this->httpClientService = $httpClientService; $this->httpClientService = $httpClientService;
$this->discoveryService = $discoveryService; $this->discoveryService = $discoveryService;
$this->jobList = $jobList; $this->jobList = $jobList;
$this->federationProviderManager = $federationProviderManager;
$this->cloudFederationFactory = $cloudFederationFactory;
} }
/** /**
@ -100,7 +114,10 @@ class Notifications {
$result = $this->tryHttpPostToShareEndpoint($remote, '', $fields); $result = $this->tryHttpPostToShareEndpoint($remote, '', $fields);
$status = json_decode($result['result'], true); $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]); \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
return true; return true;
} }
@ -271,11 +288,11 @@ class Notifications {
* @param string $remoteDomain * @param string $remoteDomain
* @param string $urlSuffix * @param string $urlSuffix
* @param array $fields post parameters * @param array $fields post parameters
* @param string $action define the action (possible values: share, reshare, accept, decline, unshare, revoke, permissions)
* @return array * @return array
* @throws \Exception * @throws \Exception
*/ */
protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) { protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields, $action="share") {
$client = $this->httpClientService->newClient();
if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) { if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) {
$remoteDomain = 'https://' . $remoteDomain; $remoteDomain = 'https://' . $remoteDomain;
@ -286,6 +303,15 @@ class Notifications {
'result' => '', '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'); $federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING');
$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares'; $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
try { try {
@ -307,4 +333,58 @@ class Notifications {
return $result; 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);
}
}
} }

@ -108,15 +108,6 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
return 'file'; return 'file';
} }
/**
* send new share to another server
*
* @since 14.0.0
*/
public function sendShare() {
// TODO: Implement sendShare() method.
}
/** /**
* share received from another server * share received from another server
* *
@ -186,6 +177,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
\OC::$server->getHTTPClientService(), \OC::$server->getHTTPClientService(),
\OC::$server->getNotificationManager(), \OC::$server->getNotificationManager(),
\OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
\OC::$server->getCloudFederationProviderManager(),
$shareWith $shareWith
); );

@ -29,6 +29,8 @@ use OCP\Federation\ICloudFederationNotification;
use OCP\Federation\ICloudFederationProvider; use OCP\Federation\ICloudFederationProvider;
use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClientService;
/** /**
* Class Manager * Class Manager
@ -45,9 +47,26 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
/** @var IAppManager */ /** @var IAppManager */
private $appManager; 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->cloudFederationProvider= [];
$this->appManager = $appManager; $this->appManager = $appManager;
$this->httpClientService = $httpClientService;
$this->cloudIdManager = $cloudIdManager;
} }
@ -103,7 +122,32 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
} }
public function sendShare(ICloudFederationShare $share) { 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) { public function sendNotification(ICloudFederationNotification $notification) {
@ -118,5 +162,30 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
public function isReady() { public function isReady() {
return $this->appManager->isEnabledForUser('cloud_federation_api', false); 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 '';
}
} }

@ -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 * @since 14.0.0
*/ */
public function getShare() { public function getShare() {
return json_encode($this->share); return $this->share;
} }
/** /**

@ -1117,7 +1117,7 @@ class Server extends ServerContainer implements IServerContainer {
}); });
$this->registerService(ICloudFederationProviderManager::class, function (Server $c) { $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) { $this->registerService(ICloudFederationFactory::class, function (Server $c) {

@ -116,7 +116,9 @@ class ProviderFactory implements IProviderFactory {
$addressHandler, $addressHandler,
$this->serverContainer->getHTTPClientService(), $this->serverContainer->getHTTPClientService(),
$this->serverContainer->query(\OCP\OCS\IDiscoveryService::class), $this->serverContainer->query(\OCP\OCS\IDiscoveryService::class),
$this->serverContainer->getJobList() $this->serverContainer->getJobList(),
\OC::$server->getCloudFederationProviderManager(),
\OC::$server->getCloudFederationFactory()
); );
$tokenHandler = new TokenHandler( $tokenHandler = new TokenHandler(
$this->serverContainer->getSecureRandom() $this->serverContainer->getSecureRandom()

@ -45,13 +45,6 @@ interface ICloudFederationProvider {
*/ */
public function getShareType(); public function getShareType();
/**
* send new share to another server
*
* @since 14.0.0
*/
public function sendShare();
/** /**
* share received from another server * share received from another server
* *

@ -123,9 +123,9 @@ interface ICloudFederationShare {
public function setShareType($shareType); 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 * @since 14.0.0
*/ */

Loading…
Cancel
Save