diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php index 4ee8344b6b..a7601d1ce1 100644 --- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php +++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php @@ -117,6 +117,7 @@ class RequestHandlerController extends Controller { * 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":{"sharedSecret":"secret","permissions":"webdav-property"}}}' http://localhost/server/index.php/ocm/shares */ public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) { + if (!$this->config->incomingRequestsEnabled()) { return new JSONResponse( ['message' => 'This server doesn\'t support outgoing federated shares'], @@ -227,7 +228,7 @@ class RequestHandlerController extends Controller { try { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType); - $provider->notificationReceived($notificationType, $providerId, $notification); + $result = $provider->notificationReceived($notificationType, $providerId, $notification); } catch (ProviderDoesNotExistsException $e) { return new JSONResponse( ['message' => $e->getMessage()], @@ -255,8 +256,7 @@ class RequestHandlerController extends Controller { ); } - - return new JSONResponse([],Http::STATUS_CREATED); + return new JSONResponse($result,Http::STATUS_CREATED); } diff --git a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php index 8514adb5e8..041232c83e 100644 --- a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php +++ b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php @@ -218,45 +218,35 @@ class RequestHandlerController extends OCSController { throw new OCSBadRequestException(); } + $notification = [ + 'sharedSecret' => $token, + 'shareWith' => $shareWith, + 'senderId' => $remoteId, + 'message' => 'Recipient of a share ask the owner to reshare the file' + ]; + try { - $share = $this->federatedShareProvider->getShareById($id); - } catch (Share\Exceptions\ShareNotFound $e) { - throw new OCSNotFoundException(); - } - - // don't allow to share a file back to the owner - list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); - $owner = $share->getShareOwner(); - $currentServer = $this->addressHandler->generateRemoteURL(); - if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) { + $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file'); + list($newToken, $localId) = $provider->notificationReceived('REQUEST_RESHARE', $id, $notification); + return new Http\DataResponse([ + 'token' => $newToken, + 'remoteId' => $localId + ]); + } catch (ProviderDoesNotExistsException $e) { + throw new OCSException('Server does not support federated cloud sharing', 503); + } catch (ShareNotFoundException $e) { + $this->logger->debug('Share not found: ' . $e->getMessage()); + } catch (ProviderCouldNotAddShareException $e) { + $this->logger->debug('Could not add reshare: ' . $e->getMessage()); throw new OCSForbiddenException(); + } catch (\Exception $e) { + $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage()); } - if ($this->verifyShare($share, $token)) { - - // check if re-sharing is allowed - if ($share->getPermissions() | ~Constants::PERMISSION_SHARE) { - $share->setPermissions($share->getPermissions() & $permission); - // the recipient of the initial share is now the initiator for the re-share - $share->setSharedBy($share->getSharedWith()); - $share->setSharedWith($shareWith); - try { - $result = $this->federatedShareProvider->create($share); - $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $remoteId); - return new Http\DataResponse([ - 'token' => $result->getToken(), - 'remoteId' => $result->getId() - ]); - } catch (\Exception $e) { - throw new OCSBadRequestException(); - } - } else { - throw new OCSForbiddenException(); - } - } throw new OCSBadRequestException(); } + /** * @NoCSRFRequired * @PublicPage diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index 84aeb8b78c..62be96dfa0 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -304,7 +304,8 @@ class FederatedShareProvider implements IShareProvider { $shareId, $remote, $shareWith, - $share->getPermissions() + $share->getPermissions(), + $share->getNode()->getName() ); return [$token, $remoteId]; diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index e0f8735f90..33254774e2 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -136,20 +136,31 @@ class Notifications { * @param string $remote remote address of the owner * @param string $shareWith * @param int $permission + * @param string $filename * @return bool * @throws \OC\HintException * @throws \OC\ServerNotAvailableException */ - public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission) { + public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename) { $fields = array( 'shareWith' => $shareWith, 'token' => $token, 'permission' => $permission, - 'remoteId' => $shareId + 'remoteId' => $shareId, ); - $result = $this->tryHttpPostToShareEndpoint(rtrim($remote, '/'), '/' . $id . '/reshare', $fields); + $ocmFields = $fields; + $ocmFields['remoteId'] = $id; + $ocmFields['localId'] = $shareId; + $ocmFields['name'] = $filename; + + $ocmResult = $this->tryOCMEndPoint($remote, $ocmFields, 'reshare'); + if (is_array($ocmResult) && isset($ocmResult['token']) && isset($ocmResult['providerId'])) { + return [$ocmResult['token'], $ocmResult['providerId']]; + } + + $result = $this->tryLegacyEndPoint(rtrim($remote, '/'), '/' . $id . '/reshare', $fields); $status = json_decode($result['result'], true); $httpRequestSuccessful = $result['success']; @@ -310,6 +321,25 @@ class Notifications { return $result; } + return $this->tryLegacyEndPoint($remoteDomain, $urlSuffix, $fields); + } + + /** + * try old federated sharing API if the OCM api doesn't work + * + * @param $remoteDomain + * @param $urlSuffix + * @param array $fields + * @return mixed + * @throws \Exception + */ + protected function tryLegacyEndPoint($remoteDomain, $urlSuffix, array $fields) { + + $result = [ + 'success' => false, + 'result' => '', + ]; + // Fall back to old API $client = $this->httpClientService->newClient(); $federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING'); @@ -332,6 +362,7 @@ class Notifications { } return $result; + } /** @@ -384,7 +415,22 @@ class Notifications { 'file' ); return $this->federationProviderManager->sendShare($share); + case 'reshare': + $notification = $this->cloudFederationFactory->getCloudFederationNotification(); + $notification->setMessage('REQUEST_RESHARE', + 'file', + $fields['remoteId'], + [ + 'sharedSecret' => $fields['token'], + 'shareWith' => $fields['shareWith'], + 'senderId' => $fields['localId'], + 'message' => 'Ask owner to reshare the file' + ] + ); + return $this->federationProviderManager->sendNotification($remoteDomain, $notification); } + return false; + } } diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php index a271fd454b..565a46c6cf 100644 --- a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php @@ -29,6 +29,7 @@ use OCA\FederatedFileSharing\FederatedShareProvider; use OCP\Activity\IManager as IActivityManager; use OCP\Activity\IManager; use OCP\App\IAppManager; +use OCP\Constants; use OCP\Federation\Exceptions\ActionNotSupportedException; use OCP\Federation\Exceptions\AuthenticationFailedException; use OCP\Federation\Exceptions\BadRequestException; @@ -258,6 +259,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { * @param string $notificationType (e.g. SHARE_ACCEPTED) * @param string $providerId id of the share * @param array $notification payload of the notification + * @return array data send back to the sender * * @throws ActionNotSupportedException * @throws AuthenticationFailedException @@ -270,11 +272,11 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { switch ($notificationType) { case 'SHARE_ACCEPTED': - $this->shareAccepted($providerId, $notification); - return; + return $this->shareAccepted($providerId, $notification); case 'SHARE_DECLINED': - $this->shareDeclined($providerId, $notification); - return; + return $this->shareDeclined($providerId, $notification); + case 'REQUEST_RESHARE': + return $this->reshareRequested($providerId, $notification); } @@ -282,9 +284,11 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } /** + * process notification that the recipient accepted a share + * * @param string $id * @param array $notification - * @return bool + * @return array * @throws ActionNotSupportedException * @throws AuthenticationFailedException * @throws BadRequestException @@ -325,7 +329,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } - return true; + return []; } /** @@ -351,14 +355,18 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } /** + * process notification that the recipient declined a share + * * @param string $id * @param array $notification + * @return array * @throws ActionNotSupportedException * @throws AuthenticationFailedException * @throws BadRequestException * @throws ShareNotFound * @throws ShareNotFoundException * @throws \OC\HintException + * */ protected function shareDeclined($id, $notification) { @@ -395,6 +403,8 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { $this->executeDeclineShare($share); + return []; + } /** @@ -424,6 +434,64 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } + /** + * recipient of a share request to re-share the file with another user + * + * @param $id + * @param $notification + * @return array + * @throws AuthenticationFailedException + * @throws BadRequestException + * @throws ProviderCouldNotAddShareException + * @throws ShareNotFoundException + * @throws ShareNotFound + */ + protected function reshareRequested($id, $notification) { + + if (!isset($notification['sharedSecret'])) { + throw new BadRequestException(['sharedSecret']); + } + $token = $notification['sharedSecret']; + + if (!isset($notification['shareWith'])) { + throw new BadRequestException(['shareWith']); + } + $shareWith = $notification['shareWith']; + + if (!isset($notification['senderId'])) { + throw new BadRequestException(['senderId']); + } + $senderId = $notification['senderId']; + + $share = $this->federatedShareProvider->getShareById($id); + // don't allow to share a file back to the owner + try { + list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); + $owner = $share->getShareOwner(); + $currentServer = $this->addressHandler->generateRemoteURL(); + if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) { + throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id); + } + } catch (\Exception $e) { + throw new ProviderCouldNotAddShareException($e->getMessage()); + } + + $this->verifyShare($share, $token); + + // check if re-sharing is allowed + if ($share->getPermissions() | ~Constants::PERMISSION_SHARE) { + // the recipient of the initial share is now the initiator for the re-share + $share->setSharedBy($share->getSharedWith()); + $share->setSharedWith($shareWith); + $result = $this->federatedShareProvider->create($share); + $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId); + return ['token' => $result->getToken(), 'providerId' => $result->getId()]; + } else { + throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id); + } + + throw new BadRequestException([]); + } /** * get file diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php index 9aab1753a4..aa25ba9dee 100644 --- a/lib/private/Federation/CloudFederationProviderManager.php +++ b/lib/private/Federation/CloudFederationProviderManager.php @@ -166,7 +166,7 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager /** * @param string $url * @param ICloudFederationNotification $notification - * @return bool + * @return mixed */ public function sendNotification($url, ICloudFederationNotification $notification) { $ocmEndPoint = $this->getOCMEndPoint($url); @@ -182,8 +182,9 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager 'timeout' => 10, 'connect_timeout' => 10, ]); - if ($response->getStatusCode() === Http::STATUS_OK) { - return true; + if ($response->getStatusCode() === Http::STATUS_CREATED) { + $result = json_decode($response->getBody(), true); + return (is_array($result)) ? $result : []; } } catch (\Exception $e) { // log the error and return false diff --git a/lib/public/Federation/ICloudFederationProvider.php b/lib/public/Federation/ICloudFederationProvider.php index 36af413cdc..5260cbf9aa 100644 --- a/lib/public/Federation/ICloudFederationProvider.php +++ b/lib/public/Federation/ICloudFederationProvider.php @@ -66,6 +66,7 @@ interface ICloudFederationProvider { * @param string $notificationType (e.g SHARE_ACCEPTED) * @param string $providerId share ID * @param array $notification provider specific notification + * @return array $data send back to sender * * @throws ShareNotFoundException * @throws ActionNotSupportedException diff --git a/lib/public/Federation/ICloudFederationProviderManager.php b/lib/public/Federation/ICloudFederationProviderManager.php index 714c6234b7..7a14e49a7b 100644 --- a/lib/public/Federation/ICloudFederationProviderManager.php +++ b/lib/public/Federation/ICloudFederationProviderManager.php @@ -77,7 +77,7 @@ interface ICloudFederationProviderManager { * send federated share * * @param ICloudFederationShare $share - * @return mixed + * @return bool * * @since 14.0.0 */ @@ -88,7 +88,7 @@ interface ICloudFederationProviderManager { * * @param string $url * @param ICloudFederationNotification $notification - * @return bool + * @return mixed * * @since 14.0.0 */