implement accept share notification

Signed-off-by: Bjoern Schiessle <bjoern@schiessle.org>
This commit is contained in:
Bjoern Schiessle 2018-05-29 16:21:13 +02:00
parent bbce8c3ea1
commit 8889e14c7c
No known key found for this signature in database
GPG Key ID: 2378A753E2BF04F6
8 changed files with 289 additions and 76 deletions

View File

@ -28,6 +28,8 @@ use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
use OCP\Federation\Exceptions\BadRequestException;
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
use OCP\Federation\Exceptions\ShareNotFoundException;
use OCP\Federation\ICloudFederationFactory;
@ -241,7 +243,12 @@ class RequestHandlerController extends Controller {
['message' => $e->getMessage()],
Http::STATUS_NOT_IMPLEMENTED
);
} catch (\Exception $e) {
} catch (BadRequestException $e) {
return new JSONResponse($e->getReturnMessage(), Http::STATUS_BAD_REQUEST);
} catch (AuthenticationFailedException $e) {
return new JSONResponse(["message" => "RESOURCE_NOT_FOUND"], Http::STATUS_FORBIDDEN);
}
catch (\Exception $e) {
return new JSONResponse(
['message' => 'Internal error at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST

View File

@ -42,6 +42,7 @@ use OCP\AppFramework\OCSController;
use OCP\Constants;
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
use OCP\Federation\Exceptions\ShareNotFoundException;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudIdManager;
@ -265,47 +266,32 @@ class RequestHandlerController extends OCSController {
* @param int $id
* @return Http\DataResponse
* @throws OCSException
* @throws Share\Exceptions\ShareNotFound
* @throws \OC\HintException
*/
public function acceptShare($id) {
if (!$this->isS2SEnabled()) {
throw new OCSException('Server does not support federated cloud sharing', 503);
}
$token = isset($_POST['token']) ? $_POST['token'] : null;
$notification = [
'sharedSecret' => $token,
'message' => 'Recipient accept the share'
];
try {
$share = $this->federatedShareProvider->getShareById($id);
} catch (Share\Exceptions\ShareNotFound $e) {
return new Http\DataResponse();
}
if ($this->verifyShare($share, $token)) {
$this->executeAcceptShare($share);
if ($share->getShareOwner() !== $share->getSharedBy()) {
list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
$remoteId = $this->federatedShareProvider->getRemoteId($share);
$this->notifications->sendAcceptShare($remote, $remoteId, $share->getToken());
}
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
$provider->notificationReceived('SHARE_ACCEPTED', $id, $notification);
} 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 (\Exception $e) {
$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage());
}
return new Http\DataResponse();
}
protected function executeAcceptShare(Share\IShare $share) {
$fileId = (int) $share->getNode()->getId();
list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
$event = \OC::$server->getActivityManager()->generateEvent();
$event->setApp('files_sharing')
->setType('remote_share')
->setAffectedUser($this->getCorrectUid($share))
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
->setObject('files', $fileId, $file)
->setLink($link);
\OC::$server->getActivityManager()->publish($event);
}
/**
* @NoCSRFRequired
* @PublicPage
@ -363,20 +349,6 @@ class RequestHandlerController extends OCSController {
}
/**
* check if we are the initiator or the owner of a re-share and return the correct UID
*
* @param Share\IShare $share
* @return string
*/
protected function getCorrectUid(Share\IShare $share) {
if ($this->userManager->userExists($share->getShareOwner())) {
return $share->getShareOwner();
}
return $share->getSharedBy();
}
/**
* @NoCSRFRequired
* @PublicPage
@ -548,24 +520,6 @@ class RequestHandlerController extends OCSController {
return $result;
}
/**
* check if we got the right share
*
* @param Share\IShare $share
* @param string $token
* @return bool
*/
protected function verifyShare(Share\IShare $share, $token) {
if (
$share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
$share->getToken() === $token
) {
return true;
}
return false;
}
/**
* @NoCSRFRequired
* @PublicPage

View File

@ -30,6 +30,7 @@
namespace OCA\FederatedFileSharing;
use OC\Share20\Share;
use OCP\Federation\Exceptions\ShareNotFoundException;
use OCP\Federation\ICloudIdManager;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Folder;
@ -708,13 +709,13 @@ class FederatedShareProvider implements IShareProvider {
$cursor->closeCursor();
if ($data === false) {
throw new ShareNotFound();
throw new ShareNotFoundException();
}
try {
$share = $this->createShareObject($data);
} catch (InvalidShare $e) {
throw new ShareNotFound();
throw new ShareNotFoundException();
}
return $share;

View File

@ -22,21 +22,29 @@
namespace OCA\FederatedFileSharing\OCM;
use OC\AppFramework\Http;
use OC\Files\Filesystem;
use OCA\Files_Sharing\Activity\Providers\RemoteShares;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\Activity\IManager as IActivityManager;
use OCP\Activity\IManager;
use OCP\App\IAppManager;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
use OCP\Federation\Exceptions\BadRequestException;
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
use OCP\Federation\Exceptions\ShareNotFoundException;
use OCP\Federation\ICloudFederationProvider;
use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\Files\NotFoundException;
use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\Notification\IManager as INotificationManager;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IShare;
use OCP\Util;
class CloudFederationProviderFiles implements ICloudFederationProvider {
@ -153,13 +161,13 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
if (!\OCP\Util::isValidFileName($name)) {
if (!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(
Util::emitHook(
'\OCA\Files_Sharing\API\Server2Server',
'preLoginNameUsedAsUserName',
array('uid' => &$shareWith)
@ -174,8 +182,8 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
$externalManager = new \OCA\Files_Sharing\External\Manager(
\OC::$server->getDatabaseConnection(),
\OC\Files\Filesystem::getMountManager(),
\OC\Files\Filesystem::getLoader(),
Filesystem::getMountManager(),
Filesystem::getLoader(),
\OC::$server->getHTTPClientService(),
\OC::$server->getNotificationManager(),
\OC::$server->query(\OCP\OCS\IDiscoveryService::class),
@ -219,7 +227,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
} catch (\Exception $e) {
$this->logger->logException($e, [
'message' => 'Server can not add remote share.',
'level' => \OCP\Util::ERROR,
'level' => Util::ERROR,
'app' => 'files_sharing'
]);
throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
@ -237,14 +245,18 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
* @param string $providerId id of the share
* @param array $notification payload of the notification
*
* @throws ShareNotFoundException
* @throws ActionNotSupportedException
*
* @throws AuthenticationFailedException
* @throws BadRequestException
* @throws ShareNotFoundException
* @throws \OC\HintException
* @since 14.0.0
*/
public function notificationReceived($notificationType, $providerId, array $notification) {
switch ($notificationType) {
case 'SHARE_ACCEPTED' :
case 'SHARE_ACCEPTED':
$this->shareAccepted($providerId, $notification);
return;
}
@ -252,6 +264,135 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
throw new ActionNotSupportedException($notification);
}
/**
* @param $id
* @param $notification
* @return bool
* @throws ActionNotSupportedException
* @throws AuthenticationFailedException
* @throws BadRequestException
* @throws ShareNotFoundException
* @throws \OC\HintException
*/
private function shareAccepted($id, $notification) {
if (!$this->isS2SEnabled(true)) {
throw new ActionNotSupportedException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
}
if (!isset($notification['sharedSecret'])) {
throw new BadRequestException(['sharedSecret']);
}
$token = $notification['sharedSecret'];
$share = $this->federatedShareProvider->getShareById($id);
$this->verifyShare($share, $token);
$this->executeAcceptShare($share);
if ($share->getShareOwner() !== $share->getSharedBy()) {
list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
$remoteId = $this->federatedShareProvider->getRemoteId($share);
$notification = $this->cloudFederationFactory->getCloudFederationNotification();
$notification->setMessage(
'SHARE_ACCEPTED',
'file',
$remoteId,
[
'sharedSecret' => $token,
'message' => 'Recipient accepted the re-share'
]
);
$this->cloudFederationProviderManager->sendNotification($remote, $notification);
}
return true;
}
/**
* @param IShare $share
* @throws ShareNotFoundException
*/
protected function executeAcceptShare(IShare $share) {
try {
$fileId = (int)$share->getNode()->getId();
list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
} catch (\Exception $e) {
throw new ShareNotFoundException();
}
$event = $this->activityManager->generateEvent();
$event->setApp('files_sharing')
->setType('remote_share')
->setAffectedUser($this->getCorrectUid($share))
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
->setObject('files', $fileId, $file)
->setLink($link);
$this->activityManager->publish($event);
}
/**
* get file
*
* @param string $user
* @param int $fileSource
* @return array with internal path of the file and a absolute link to it
*/
private function getFile($user, $fileSource) {
\OC_Util::setupFS($user);
try {
$file = Filesystem::getPath($fileSource);
} catch (NotFoundException $e) {
$file = null;
}
$args = Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file);
$link = Util::linkToAbsolute('files', 'index.php', $args);
return array($file, $link);
}
/**
* check if we are the initiator or the owner of a re-share and return the correct UID
*
* @param IShare $share
* @return string
*/
protected function getCorrectUid(IShare $share) {
if ($this->userManager->userExists($share->getShareOwner())) {
return $share->getShareOwner();
}
return $share->getSharedBy();
}
/**
* check if we got the right share
*
* @param IShare $share
* @param string $token
* @return bool
* @throws AuthenticationFailedException
*/
protected function verifyShare(IShare $share, $token) {
if (
$share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
$share->getToken() === $token
) {
return true;
}
throw new AuthenticationFailedException();
}
/**
* check if server-to-server sharing is enabled
*

View File

@ -0,0 +1,40 @@
<?php
/**
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Federation\Exceptions;
use OC\HintException;
class AuthenticationFailedException extends HintException {
/**
* BadRequestException constructor.
*
* @param array $missingParameters
*/
public function __construct() {
$l = \OC::$server->getL10N('federation');
$message = 'Authentication failed, wrong token or provider ID given';
$hint = $l->t('Authentication failed, wrong token or provider ID given');
parent::__construct($message, $hint);
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Federation\Exceptions;
use OC\HintException;
class BadRequestException extends HintException {
private $parameterList;
/**
* BadRequestException constructor.
*
* @param array $missingParameters
*/
public function __construct(array $missingParameters) {
$l = \OC::$server->getL10N('federation');
$this->parameterList = $missingParameters;
$parameterList = implode(',', $missingParameters);
$message = 'Parameters missing in order to complete the request. Missing Parameters: ' . $parameterList;
$hint = $l->t('Parameters missing in order to complete the request. Missing Parameters: "%s"', [$parameterList]);
parent::__construct($message, $hint);
}
/**
* get array with the return message as defined in the OCM API
*
* @return array
*/
public function getReturnMessage() {
$result = [
'message' => 'RESOURCE_NOT_FOUND',
'validationErrors' =>[
]
];
foreach ($this->parameterList as $missingParameter) {
$result['validationErrors'] = [
'name' => $missingParameter,
'message' => 'NOT_FOUND'
];
}
return $result;
}
}

View File

@ -22,6 +22,8 @@
namespace OCP\Federation;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
use OCP\Federation\Exceptions\BadRequestException;
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
use OCP\Federation\Exceptions\ShareNotFoundException;
@ -67,6 +69,8 @@ interface ICloudFederationProvider {
*
* @throws ShareNotFoundException
* @throws ActionNotSupportedException
* @throws BadRequestException
* @throws AuthenticationFailedException
*
* @since 14.0.0
*/

View File

@ -24,8 +24,8 @@
namespace OCP\Share;
use OCP\Federation\Exceptions\ShareNotFoundException;
use OCP\Files\Folder;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Files\Node;
/**
@ -125,7 +125,7 @@ interface IShareProvider {
* @param int $id
* @param string|null $recipientId
* @return \OCP\Share\IShare
* @throws ShareNotFound
* @throws ShareNotFoundException
* @since 9.0.0
*/
public function getShareById($id, $recipientId = null);