aboutsummaryrefslogtreecommitdiffstats
path: root/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/federatedfilesharing/lib/Controller/RequestHandlerController.php')
-rw-r--r--apps/federatedfilesharing/lib/Controller/RequestHandlerController.php754
1 files changed, 256 insertions, 498 deletions
diff --git a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php
index a74342f1182..7fdd718cbfe 100644
--- a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php
+++ b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php
@@ -1,466 +1,278 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\FederatedFileSharing\Controller;
-use OCA\Files_Sharing\Activity\Providers\RemoteShares;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\FederatedFileSharing\Notifications;
+use OCP\App\IAppManager;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\Attribute\OpenAPI;
+use OCP\AppFramework\Http\Attribute\PublicPage;
+use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCS\OCSException;
-use OCP\AppFramework\OCS\OCSForbiddenException;
-use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\Constants;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
+use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
+use OCP\Federation\ICloudFederationFactory;
+use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudIdManager;
-use OCP\Files\NotFoundException;
+use OCP\HintException;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\IUserManager;
+use OCP\Log\Audit\CriticalActionPerformedEvent;
+use OCP\Server;
use OCP\Share;
-use OCP\Share\IShare;
+use OCP\Share\Exceptions\ShareNotFound;
+use Psr\Log\LoggerInterface;
+#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)]
class RequestHandlerController extends OCSController {
- /** @var FederatedShareProvider */
- private $federatedShareProvider;
-
- /** @var IDBConnection */
- private $connection;
-
- /** @var Share\IManager */
- private $shareManager;
-
- /** @var Notifications */
- private $notifications;
-
- /** @var AddressHandler */
- private $addressHandler;
-
- /** @var IUserManager */
- private $userManager;
-
- /** @var string */
- private $shareTable = 'share';
-
- /** @var ICloudIdManager */
- private $cloudIdManager;
-
- /**
- * Server2Server constructor.
- *
- * @param string $appName
- * @param IRequest $request
- * @param FederatedShareProvider $federatedShareProvider
- * @param IDBConnection $connection
- * @param Share\IManager $shareManager
- * @param Notifications $notifications
- * @param AddressHandler $addressHandler
- * @param IUserManager $userManager
- * @param ICloudIdManager $cloudIdManager
- */
- public function __construct($appName,
- IRequest $request,
- FederatedShareProvider $federatedShareProvider,
- IDBConnection $connection,
- Share\IManager $shareManager,
- Notifications $notifications,
- AddressHandler $addressHandler,
- IUserManager $userManager,
- ICloudIdManager $cloudIdManager
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private FederatedShareProvider $federatedShareProvider,
+ private IDBConnection $connection,
+ private Share\IManager $shareManager,
+ private Notifications $notifications,
+ private AddressHandler $addressHandler,
+ private IUserManager $userManager,
+ private ICloudIdManager $cloudIdManager,
+ private LoggerInterface $logger,
+ private ICloudFederationFactory $cloudFederationFactory,
+ private ICloudFederationProviderManager $cloudFederationProviderManager,
+ private IEventDispatcher $eventDispatcher,
) {
parent::__construct($appName, $request);
-
- $this->federatedShareProvider = $federatedShareProvider;
- $this->connection = $connection;
- $this->shareManager = $shareManager;
- $this->notifications = $notifications;
- $this->addressHandler = $addressHandler;
- $this->userManager = $userManager;
- $this->cloudIdManager = $cloudIdManager;
}
/**
- * @NoCSRFRequired
- * @PublicPage
- *
* create a new share
*
- * @return Http\DataResponse
+ * @param string|null $remote Address of the remote
+ * @param string|null $token Shared secret between servers
+ * @param string|null $name Name of the shared resource
+ * @param string|null $owner Display name of the receiver
+ * @param string|null $sharedBy Display name of the sender
+ * @param string|null $shareWith ID of the user that receives the share
+ * @param int|null $remoteId ID of the remote
+ * @param string|null $sharedByFederatedId Federated ID of the sender
+ * @param string|null $ownerFederatedId Federated ID of the receiver
+ * @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: Share created successfully
*/
- public function createShare() {
-
- if (!$this->isS2SEnabled(true)) {
- throw new OCSException('Server does not support federated cloud sharing', 503);
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function createShare(
+ ?string $remote = null,
+ ?string $token = null,
+ ?string $name = null,
+ ?string $owner = null,
+ ?string $sharedBy = null,
+ ?string $shareWith = null,
+ ?int $remoteId = null,
+ ?string $sharedByFederatedId = null,
+ ?string $ownerFederatedId = null,
+ ) {
+ if ($ownerFederatedId === null) {
+ $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
+ }
+ // if the owner of the share and the initiator are the same user
+ // we also complete the federated share ID for the initiator
+ if ($sharedByFederatedId === null && $owner === $sharedBy) {
+ $sharedByFederatedId = $ownerFederatedId;
}
- $remote = isset($_POST['remote']) ? $_POST['remote'] : null;
- $token = isset($_POST['token']) ? $_POST['token'] : null;
- $name = isset($_POST['name']) ? $_POST['name'] : null;
- $owner = isset($_POST['owner']) ? $_POST['owner'] : null;
- $sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
- $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
- $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
- $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
- $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
-
- if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
-
- if (!\OCP\Util::isValidFileName($name)) {
- throw new OCSException('The mountpoint name contains invalid characters.', 400);
- }
-
- // FIXME this should be a method in the user management instead
- \OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG);
- \OCP\Util::emitHook(
- '\OCA\Files_Sharing\API\Server2Server',
- 'preLoginNameUsedAsUserName',
- array('uid' => &$shareWith)
- );
- \OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG);
-
- if (!\OC::$server->getUserManager()->userExists($shareWith)) {
- throw new OCSException('User does not exists', 400);
- }
+ $share = $this->cloudFederationFactory->getCloudFederationShare(
+ $shareWith,
+ $name,
+ '',
+ $remoteId,
+ $ownerFederatedId,
+ $owner,
+ $sharedByFederatedId,
+ $sharedBy,
+ $token,
+ 'user',
+ 'file'
+ );
- \OC_Util::setupFS($shareWith);
-
- $externalManager = new \OCA\Files_Sharing\External\Manager(
- \OC::$server->getDatabaseConnection(),
- \OC\Files\Filesystem::getMountManager(),
- \OC\Files\Filesystem::getLoader(),
- \OC::$server->getHTTPClientService(),
- \OC::$server->getNotificationManager(),
- \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
- $shareWith
- );
-
- try {
- $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
- $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
-
- if ($ownerFederatedId === null) {
- $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
- }
- // if the owner of the share and the initiator are the same user
- // we also complete the federated share ID for the initiator
- if ($sharedByFederatedId === null && $owner === $sharedBy) {
- $sharedByFederatedId = $ownerFederatedId;
- }
-
- $event = \OC::$server->getActivityManager()->generateEvent();
- $event->setApp('files_sharing')
- ->setType('remote_share')
- ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
- ->setAffectedUser($shareWith)
- ->setObject('remote_share', (int)$shareId, $name);
- \OC::$server->getActivityManager()->publish($event);
-
- $urlGenerator = \OC::$server->getURLGenerator();
-
- $notificationManager = \OC::$server->getNotificationManager();
- $notification = $notificationManager->createNotification();
- $notification->setApp('files_sharing')
- ->setUser($shareWith)
- ->setDateTime(new \DateTime())
- ->setObject('remote_share', $shareId)
- ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
-
- $declineAction = $notification->createAction();
- $declineAction->setLabel('decline')
- ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
- $notification->addAction($declineAction);
-
- $acceptAction = $notification->createAction();
- $acceptAction->setLabel('accept')
- ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
- $notification->addAction($acceptAction);
-
- $notificationManager->notify($notification);
-
- return new Http\DataResponse();
- } catch (\Exception $e) {
- \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR);
- throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
+ try {
+ $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
+ $provider->shareReceived($share);
+ if ($sharedByFederatedId === $ownerFederatedId) {
+ $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new federated share with "%s" was created by "%s" and shared with "%s"', [$name, $ownerFederatedId, $shareWith]));
+ } else {
+ $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new federated share with "%s" was shared by "%s" (resource owner is: "%s") and shared with "%s"', [$name, $sharedByFederatedId, $ownerFederatedId, $shareWith]));
}
+ } catch (ProviderDoesNotExistsException $e) {
+ throw new OCSException('Server does not support federated cloud sharing', 503);
+ } catch (ProviderCouldNotAddShareException $e) {
+ throw new OCSException($e->getMessage(), 400);
+ } catch (\Exception $e) {
+ throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
}
- throw new OCSException('server can not add remote share, missing parameter', 400);
+ return new DataResponse();
}
/**
- * @NoCSRFRequired
- * @PublicPage
- *
* create re-share on behalf of another user
*
- * @param int $id
- * @return Http\DataResponse
- * @throws OCSBadRequestException
- * @throws OCSForbiddenException
- * @throws OCSNotFoundException
+ * @param int $id ID of the share
+ * @param string|null $token Shared secret between servers
+ * @param string|null $shareWith ID of the user that receives the share
+ * @param int|null $remoteId ID of the remote
+ * @return Http\DataResponse<Http::STATUS_OK, array{token: string, remoteId: string}, array{}>
+ * @throws OCSBadRequestException Re-sharing is not possible
+ * @throws OCSException
+ *
+ * 200: Remote share returned
*/
- public function reShare($id) {
-
- $token = $this->request->getParam('token', null);
- $shareWith = $this->request->getParam('shareWith', null);
- $permission = (int)$this->request->getParam('permission', null);
- $remoteId = (int)$this->request->getParam('remoteId', null);
-
- if ($id === null ||
- $token === null ||
- $shareWith === null ||
- $permission === null ||
- $remoteId === null
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function reShare(int $id, ?string $token = null, ?string $shareWith = null, ?int $remoteId = 0) {
+ if ($token === null
+ || $shareWith === null
+ || $remoteId === null
) {
throw new OCSBadRequestException();
}
- try {
- $share = $this->federatedShareProvider->getShareById($id);
- } catch (Share\Exceptions\ShareNotFound $e) {
- throw new OCSNotFoundException();
- }
+ $notification = [
+ 'sharedSecret' => $token,
+ 'shareWith' => $shareWith,
+ 'senderId' => $remoteId,
+ 'message' => 'Recipient of a share ask the owner to reshare the file'
+ ];
- // 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)) {
- throw new OCSForbiddenException();
+ try {
+ $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
+ [$newToken, $localId] = $provider->notificationReceived('REQUEST_RESHARE', $id, $notification);
+ return new DataResponse([
+ 'token' => $newToken,
+ 'remoteId' => $localId
+ ]);
+ } catch (ProviderDoesNotExistsException $e) {
+ throw new OCSException('Server does not support federated cloud sharing', 503);
+ } catch (ShareNotFound $e) {
+ $this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
+ } catch (\Exception $e) {
+ $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
}
- 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
- *
* accept server-to-server share
*
- * @param int $id
- * @return Http\DataResponse
+ * @param int $id ID of the remote share
+ * @param string|null $token Shared secret between servers
+ * @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ * @throws ShareNotFound
+ * @throws HintException
+ *
+ * 200: Share accepted successfully
*/
- 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;
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function acceptShare(int $id, ?string $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);
+ $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was accepted', [$id]));
+ } catch (ProviderDoesNotExistsException $e) {
+ throw new OCSException('Server does not support federated cloud sharing', 503);
+ } catch (ShareNotFound $e) {
+ $this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
+ } catch (\Exception $e) {
+ $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
}
- 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);
+ return new DataResponse();
}
/**
- * @NoCSRFRequired
- * @PublicPage
- *
* decline server-to-server share
*
- * @param int $id
- * @return Http\DataResponse
+ * @param int $id ID of the remote share
+ * @param string|null $token Shared secret between servers
+ * @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
- */
- public function declineShare($id) {
-
- if (!$this->isS2SEnabled()) {
- throw new OCSException('Server does not support federated cloud sharing', 503);
- }
-
- $token = isset($_POST['token']) ? $_POST['token'] : null;
-
- try {
- $share = $this->federatedShareProvider->getShareById($id);
- } catch (Share\Exceptions\ShareNotFound $e) {
- return new Http\DataResponse();
- }
-
- if ($this->verifyShare($share, $token)) {
- if ($share->getShareOwner() !== $share->getSharedBy()) {
- list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
- $remoteId = $this->federatedShareProvider->getRemoteId($share);
- $this->notifications->sendDeclineShare($remote, $remoteId, $share->getToken());
- }
- $this->executeDeclineShare($share);
- }
-
- return new Http\DataResponse();
- }
-
- /**
- * delete declined share and create a activity
*
- * @param Share\IShare $share
+ * 200: Share declined successfully
*/
- protected function executeDeclineShare(Share\IShare $share) {
- $this->federatedShareProvider->removeShareFromTable($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_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
- ->setObject('files', $fileId, $file)
- ->setLink($link);
- \OC::$server->getActivityManager()->publish($event);
-
- }
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function declineShare(int $id, ?string $token = null) {
+ $notification = [
+ 'sharedSecret' => $token,
+ 'message' => 'Recipient declined the share'
+ ];
- /**
- * 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();
+ try {
+ $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
+ $provider->notificationReceived('SHARE_DECLINED', $id, $notification);
+ $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was declined', [$id]));
+ } catch (ProviderDoesNotExistsException $e) {
+ throw new OCSException('Server does not support federated cloud sharing', 503);
+ } catch (ShareNotFound $e) {
+ $this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
+ } catch (\Exception $e) {
+ $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
}
- return $share->getSharedBy();
+ return new DataResponse();
}
/**
- * @NoCSRFRequired
- * @PublicPage
- *
* remove server-to-server share if it was unshared by the owner
*
- * @param int $id
- * @return Http\DataResponse
+ * @param int $id ID of the share
+ * @param string|null $token Shared secret between servers
+ * @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: Share unshared successfully
*/
- public function unshare($id) {
-
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function unshare(int $id, ?string $token = null) {
if (!$this->isS2SEnabled()) {
throw new OCSException('Server does not support federated cloud sharing', 503);
}
- $token = isset($_POST['token']) ? $_POST['token'] : null;
-
- $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?');
- $query->execute(array($id, $token));
- $share = $query->fetchRow();
-
- if ($token && $id && !empty($share)) {
-
- $remote = $this->cleanupRemote($share['remote']);
-
- $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
- $mountpoint = $share['mountpoint'];
- $user = $share['user'];
-
- $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?');
- $query->execute(array($id, $token));
-
- if ($share['accepted']) {
- $path = trim($mountpoint, '/');
- } else {
- $path = trim($share['name'], '/');
- }
-
- $notificationManager = \OC::$server->getNotificationManager();
- $notification = $notificationManager->createNotification();
- $notification->setApp('files_sharing')
- ->setUser($share['user'])
- ->setObject('remote_share', (int)$share['id']);
- $notificationManager->markProcessed($notification);
-
- $event = \OC::$server->getActivityManager()->generateEvent();
- $event->setApp('files_sharing')
- ->setType('remote_share')
- ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
- ->setAffectedUser($user)
- ->setObject('remote_share', (int)$share['id'], $path);
- \OC::$server->getActivityManager()->publish($event);
+ try {
+ $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
+ $notification = ['sharedSecret' => $token];
+ $provider->notificationReceived('SHARE_UNSHARED', $id, $notification);
+ $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was unshared', [$id]));
+ } catch (\Exception $e) {
+ $this->logger->debug('processing unshare notification failed: ' . $e->getMessage(), ['exception' => $e]);
}
- return new Http\DataResponse();
+ return new DataResponse();
}
private function cleanupRemote($remote) {
@@ -471,71 +283,26 @@ class RequestHandlerController extends OCSController {
/**
- * @NoCSRFRequired
- * @PublicPage
- *
* federated share was revoked, either by the owner or the re-sharer
*
- * @param int $id
- * @return Http\DataResponse
- * @throws OCSBadRequestException
- */
- public function revoke($id) {
- $token = $this->request->getParam('token');
-
- $share = $this->federatedShareProvider->getShareById($id);
-
- if ($this->verifyShare($share, $token)) {
- $this->federatedShareProvider->removeShareFromTable($share);
- return new Http\DataResponse();
- }
-
- throw new OCSBadRequestException();
- }
-
- /**
- * get share
+ * @param int $id ID of the share
+ * @param string|null $token Shared secret between servers
+ * @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSBadRequestException Revoking the share is not possible
*
- * @param int $id
- * @param string $token
- * @return array|bool
+ * 200: Share revoked successfully
*/
- protected function getShare($id, $token) {
- $query = $this->connection->getQueryBuilder();
- $query->select('*')->from($this->shareTable)
- ->where($query->expr()->eq('token', $query->createNamedParameter($token)))
- ->andWhere($query->expr()->eq('share_type', $query->createNamedParameter(FederatedShareProvider::SHARE_TYPE_REMOTE)))
- ->andWhere($query->expr()->eq('id', $query->createNamedParameter($id)));
-
- $result = $query->execute()->fetchAll();
-
- if (!empty($result) && isset($result[0])) {
- return $result[0];
- }
-
- return false;
- }
-
- /**
- * 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);
-
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function revoke(int $id, ?string $token = null) {
try {
- $file = \OC\Files\Filesystem::getPath($fileSource);
- } catch (NotFoundException $e) {
- $file = null;
+ $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
+ $notification = ['sharedSecret' => $token];
+ $provider->notificationReceived('RESHARE_UNDO', $id, $notification);
+ return new DataResponse();
+ } catch (\Exception $e) {
+ throw new OCSBadRequestException();
}
- $args = \OC\Files\Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file);
- $link = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
-
- return array($file, $link);
-
}
/**
@@ -545,8 +312,7 @@ class RequestHandlerController extends OCSController {
* @return bool
*/
private function isS2SEnabled($incoming = false) {
-
- $result = \OCP\App::isEnabled('files_sharing');
+ $result = Server::get(IAppManager::class)->isEnabledForUser('files_sharing');
if ($incoming) {
$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
@@ -558,88 +324,80 @@ class RequestHandlerController extends OCSController {
}
/**
- * check if we got the right share
+ * update share information to keep federated re-shares in sync
*
- * @param Share\IShare $share
- * @param string $token
- * @return bool
+ * @param int $id ID of the share
+ * @param string|null $token Shared secret between servers
+ * @param int|null $permissions New permissions
+ * @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSBadRequestException Updating permissions is not possible
+ *
+ * 200: Permissions updated successfully
*/
- protected function verifyShare(Share\IShare $share, $token) {
- if (
- $share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
- $share->getToken() === $token
- ) {
- return true;
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function updatePermissions(int $id, ?string $token = null, ?int $permissions = null) {
+ $ncPermissions = $permissions;
+
+ try {
+ $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
+ $ocmPermissions = $this->ncPermissions2ocmPermissions((int)$ncPermissions);
+ $notification = ['sharedSecret' => $token, 'permission' => $ocmPermissions];
+ $provider->notificationReceived('RESHARE_CHANGE_PERMISSION', $id, $notification);
+ $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" has updated permissions "%s"', [$id, implode(', ', $ocmPermissions)]));
+ } catch (\Exception $e) {
+ $this->logger->debug($e->getMessage(), ['exception' => $e]);
+ throw new OCSBadRequestException();
}
- return false;
+ return new DataResponse();
}
/**
- * @NoCSRFRequired
- * @PublicPage
- *
- * update share information to keep federated re-shares in sync
+ * translate Nextcloud permissions to OCM Permissions
*
- * @param int $id
- * @return Http\DataResponse
- * @throws OCSBadRequestException
+ * @param $ncPermissions
+ * @return array
*/
- public function updatePermissions($id) {
- $token = $this->request->getParam('token', null);
- $permissions = $this->request->getParam('permissions', null);
+ protected function ncPermissions2ocmPermissions($ncPermissions) {
+ $ocmPermissions = [];
- try {
- $share = $this->federatedShareProvider->getShareById($id);
- } catch (Share\Exceptions\ShareNotFound $e) {
- throw new OCSBadRequestException();
+ if ($ncPermissions & Constants::PERMISSION_SHARE) {
+ $ocmPermissions[] = 'share';
}
- $validPermission = ctype_digit($permissions);
- $validToken = $this->verifyShare($share, $token);
- if ($validPermission && $validToken) {
- $this->updatePermissionsInDatabase($share, (int)$permissions);
- } else {
- throw new OCSBadRequestException();
+ if ($ncPermissions & Constants::PERMISSION_READ) {
+ $ocmPermissions[] = 'read';
}
- return new Http\DataResponse();
- }
+ if (($ncPermissions & Constants::PERMISSION_CREATE)
+ || ($ncPermissions & Constants::PERMISSION_UPDATE)) {
+ $ocmPermissions[] = 'write';
+ }
- /**
- * update permissions in database
- *
- * @param IShare $share
- * @param int $permissions
- */
- protected function updatePermissionsInDatabase(IShare $share, $permissions) {
- $query = $this->connection->getQueryBuilder();
- $query->update('share')
- ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
- ->set('permissions', $query->createNamedParameter($permissions))
- ->execute();
+ return $ocmPermissions;
}
/**
- * @NoCSRFRequired
- * @PublicPage
- *
* change the owner of a server-to-server share
*
- * @param int $id
- * @return Http\DataResponse
- * @throws \InvalidArgumentException
- * @throws OCSException
+ * @param int $id ID of the share
+ * @param string|null $token Shared secret between servers
+ * @param string|null $remote Address of the remote
+ * @param string|null $remote_id ID of the remote
+ * @return Http\DataResponse<Http::STATUS_OK, array{remote: string, owner: string}, array{}>
+ * @throws OCSBadRequestException Moving share is not possible
+ *
+ * 200: Share moved successfully
*/
- public function move($id) {
-
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function move(int $id, ?string $token = null, ?string $remote = null, ?string $remote_id = null) {
if (!$this->isS2SEnabled()) {
throw new OCSException('Server does not support federated cloud sharing', 503);
}
- $token = $this->request->getParam('token');
- $remote = $this->request->getParam('remote');
- $newRemoteId = $this->request->getParam('remote_id', $id);
+ $newRemoteId = (string)($remote_id ?? $id);
$cloudId = $this->cloudIdManager->resolveCloudId($remote);
$qb = $this->connection->getQueryBuilder();
@@ -649,10 +407,10 @@ class RequestHandlerController extends OCSController {
->set('remote_id', $qb->createNamedParameter($newRemoteId))
->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
- $affected = $query->execute();
+ $affected = $query->executeStatement();
if ($affected > 0) {
- return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
+ return new DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
} else {
throw new OCSBadRequestException('Share not found or token invalid');
}