diff options
author | Bjoern Schiessle <bjoern@schiessle.org> | 2018-06-13 14:19:59 +0200 |
---|---|---|
committer | Bjoern Schiessle <bjoern@schiessle.org> | 2018-07-11 10:11:44 +0200 |
commit | b23032e4c569f7ba54197171cbb02ed8119b6811 (patch) | |
tree | 882cc64ab6398f33962428d79aa270055a20f6e0 /apps/federatedfilesharing/lib | |
parent | c8631d607ef827f0eb29312faf7b2b808e1a8e7d (diff) | |
download | nextcloud-server-b23032e4c569f7ba54197171cbb02ed8119b6811.tar.gz nextcloud-server-b23032e4c569f7ba54197171cbb02ed8119b6811.zip |
implement federated group shares
Signed-off-by: Bjoern Schiessle <bjoern@schiessle.org>
Diffstat (limited to 'apps/federatedfilesharing/lib')
4 files changed, 122 insertions, 49 deletions
diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 70347831211..73ac062be09 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -65,7 +65,8 @@ class Application extends App { $server->getURLGenerator(), $server->getCloudFederationFactory(), $server->getCloudFederationProviderManager(), - $server->getDatabaseConnection() + $server->getDatabaseConnection(), + $server->getGroupManager() ); }); @@ -145,7 +146,9 @@ class Application extends App { \OC::$server->getConfig(), \OC::$server->getUserManager(), \OC::$server->getCloudIdManager(), - $c->query(IConfig::class) + $c->query(IConfig::class), + \OC::$server->getCloudFederationProviderManager() + ); } diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index d32560c4ffd..d1560d90ef5 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -96,6 +96,9 @@ class FederatedShareProvider implements IShareProvider { /** @var ICloudFederationProviderManager */ private $cloudFederationProviderManager; + /** @var array list of supported share types */ + private $supportedShareType = [\OCP\Share::SHARE_TYPE_REMOTE_GROUP, \OCP\Share::SHARE_TYPE_REMOTE]; + /** * DefaultShareProvider constructor. * @@ -164,12 +167,23 @@ class FederatedShareProvider implements IShareProvider { $itemType = $share->getNodeType(); $permissions = $share->getPermissions(); $sharedBy = $share->getSharedBy(); + $shareType = $share->getShareType(); + + if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE_GROUP && + !$this->isOutgoingServer2serverGroupShareEnabled() + ) { + $message = 'It is not allowed to send federated group shares from this server.'; + $message_t = $this->l->t('It is not allowed to send federated group shares from this server.'); + $this->logger->debug($message, ['app' => 'Federated File Sharing']); + throw new \Exception($message_t); + } /* * Check if file is not already shared with the remote user */ - $alreadyShared = $this->getSharedWith($shareWith, self::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0); - if (!empty($alreadyShared)) { + $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0); + $alreadySharedGroup = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE_GROUP, $share->getNode(), 1, 0); + if (!empty($alreadyShared) || !empty($alreadySharedGroup)) { $message = 'Sharing %s failed, because this item is already shared with %s'; $message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith)); $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); @@ -200,7 +214,7 @@ class FederatedShareProvider implements IShareProvider { if ($remoteShare) { try { $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']); - $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time()); + $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType); $share->setId($shareId); list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); // remote share was create successfully if we get a valid token as return @@ -245,7 +259,8 @@ class FederatedShareProvider implements IShareProvider { $share->getSharedBy(), $share->getShareOwner(), $share->getPermissions(), - $token + $token, + $share->getShareType() ); $failure = false; @@ -265,7 +280,8 @@ class FederatedShareProvider implements IShareProvider { $share->getShareOwner(), $ownerCloudId->getId(), $share->getSharedBy(), - $sharedByFederatedId + $sharedByFederatedId, + $share->getShareType() ); if ($send === false) { @@ -349,12 +365,13 @@ class FederatedShareProvider implements IShareProvider { * @param string $uidOwner * @param int $permissions * @param string $token + * @param int $shareType * @return int */ - private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) { + private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) { $qb = $this->dbConnection->getQueryBuilder(); $qb->insert('share') - ->setValue('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)) + ->setValue('share_type', $qb->createNamedParameter($shareType)) ->setValue('item_type', $qb->createNamedParameter($itemType)) ->setValue('item_source', $qb->createNamedParameter($itemSource)) ->setValue('file_source', $qb->createNamedParameter($itemSource)) @@ -498,7 +515,7 @@ class FederatedShareProvider implements IShareProvider { $qb->select('*') ->from('share') ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))) + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) ->orderBy('id'); $cursor = $qb->execute(); @@ -647,7 +664,7 @@ class FederatedShareProvider implements IShareProvider { $qb->select('*') ->from('share'); - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))); + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); /** * Reshares for this user are shares where they are the owner. @@ -704,7 +721,7 @@ class FederatedShareProvider implements IShareProvider { $qb->select('*') ->from('share') ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))); + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); $cursor = $qb->execute(); $data = $cursor->fetch(); @@ -732,10 +749,11 @@ class FederatedShareProvider implements IShareProvider { public function getSharesByPath(Node $path) { $qb = $this->dbConnection->getQueryBuilder(); + // get federated user shares $cursor = $qb->select('*') ->from('share') ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))) + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) ->execute(); $shares = []; @@ -768,7 +786,7 @@ class FederatedShareProvider implements IShareProvider { } $qb->setFirstResult($offset); - $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))); + $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); // Filter by node if provided @@ -799,7 +817,7 @@ class FederatedShareProvider implements IShareProvider { $cursor = $qb->select('*') ->from('share') - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))) + ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) ->execute(); diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index fdba3e113d6..70733bc9e2c 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -88,11 +88,12 @@ class Notifications { * @param string $ownerFederatedId * @param string $sharedBy * @param string $sharedByFederatedId + * @param int $shareType (can be a remote user or group share) * @return bool * @throws \OC\HintException * @throws \OC\ServerNotAvailableException */ - public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId) { + public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType) { list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); @@ -109,6 +110,7 @@ class Notifications { 'sharedBy' => $sharedBy, 'sharedByFederatedId' => $sharedByFederatedId, 'remote' => $local, + 'shareType' => $shareType ); $result = $this->tryHttpPostToShareEndpoint($remote, '', $fields); @@ -392,7 +394,7 @@ class Notifications { $fields['sharedByFederatedId'], $fields['sharedBy'], $fields['token'], - 'user', + $fields['shareType'], 'file' ); return $this->federationProviderManager->sendShare($share); @@ -406,6 +408,7 @@ class Notifications { 'sharedSecret' => $fields['token'], 'shareWith' => $fields['shareWith'], 'senderId' => $fields['localId'], + 'shareType' => $fields['shareType'], 'message' => 'Ask owner to reshare the file' ] ); diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php index 00750f924ef..cb7b6478e77 100644 --- a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php @@ -40,10 +40,12 @@ use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudIdManager; use OCP\Files\NotFoundException; use OCP\IDBConnection; +use OCP\IGroupManager; use OCP\ILogger; use OCP\IURLGenerator; use OCP\IUserManager; use OCP\Notification\IManager as INotificationManager; +use OCP\Share; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IShare; use OCP\Util; @@ -86,6 +88,9 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { /** @var IDBConnection */ private $connection; + /** @var IGroupManager */ + private $groupManager; + /** * CloudFederationProvider constructor. * @@ -101,6 +106,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { * @param ICloudFederationFactory $cloudFederationFactory * @param ICloudFederationProviderManager $cloudFederationProviderManager * @param IDBConnection $connection + * @param IGroupManager $groupManager */ public function __construct(IAppManager $appManager, FederatedShareProvider $federatedShareProvider, @@ -113,7 +119,8 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { IURLGenerator $urlGenerator, ICloudFederationFactory $cloudFederationFactory, ICloudFederationProviderManager $cloudFederationProviderManager, - IDBConnection $connection + IDBConnection $connection, + IGroupManager $groupManager ) { $this->appManager = $appManager; $this->federatedShareProvider = $federatedShareProvider; @@ -127,6 +134,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { $this->cloudFederationFactory = $cloudFederationFactory; $this->cloudFederationProviderManager = $cloudFederationProviderManager; $this->connection = $connection; + $this->groupManager = $groupManager; } @@ -175,6 +183,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { $remoteId = $share->getProviderId(); $sharedByFederatedId = $share->getSharedBy(); $ownerFederatedId = $share->getOwner(); + $shareType = $this->mapShareTypeToNextcloud($share->getShareType()); // if no explicit information about the person who created the share was send // we assume that the share comes from the owner @@ -190,19 +199,25 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } // FIXME this should be a method in the user management instead - $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']); - Util::emitHook( - '\OCA\Files_Sharing\API\Server2Server', - 'preLoginNameUsedAsUserName', - array('uid' => &$shareWith) - ); - $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']); + if ($shareType === Share::SHARE_TYPE_USER) { + $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']); + Util::emitHook( + '\OCA\Files_Sharing\API\Server2Server', + 'preLoginNameUsedAsUserName', + array('uid' => &$shareWith) + ); + $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']); - if (!$this->userManager->userExists($shareWith)) { - throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST); + if (!$this->userManager->userExists($shareWith)) { + throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST); + } + + \OC_Util::setupFS($shareWith); } - \OC_Util::setupFS($shareWith); + if ($shareType === Share::SHARE_TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) { + throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST); + } $externalManager = new \OCA\Files_Sharing\External\Manager( \OC::$server->getDatabaseConnection(), @@ -217,7 +232,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { ); try { - $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); + $externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId); $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); $event = $this->activityManager->generateEvent(); @@ -228,25 +243,14 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { ->setObject('remote_share', (int)$shareId, $name); \OC::$server->getActivityManager()->publish($event); - $notification = $this->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($this->urlGenerator->getAbsoluteURL($this->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($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); - $notification->addAction($acceptAction); - - $this->notificationManager->notify($notification); - + if ($shareType === Share::SHARE_TYPE_USER) { + $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name); + } else { + $groupMembers = $this->groupManager->get($shareWith)->getUsers(); + foreach ($groupMembers as $user) { + $this->notifyAboutNewShare($user, $shareId, $ownerFederatedId, $sharedByFederatedId, $name); + } + } return $shareId; } catch (\Exception $e) { $this->logger->logException($e, [ @@ -298,6 +302,51 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { } /** + * map OCM share type (strings) to Nextcloud internal share types (integer) + * + * @param string $shareType + * @return int + */ + private function mapShareTypeToNextcloud($shareType) { + $result = Share::SHARE_TYPE_USER; + if ($shareType === 'group') { + $result = Share::SHARE_TYPE_GROUP; + } + + return $result; + } + + /** + * notify user about new federated share + * + * @param $shareWith + * @param $shareId + * @param $ownerFederatedId + * @param $sharedByFederatedId + * @param $name + */ + private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name) { + $notification = $this->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($this->urlGenerator->getAbsoluteURL($this->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($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); + $notification->addAction($acceptAction); + + $this->notificationManager->notify($notification); + } + + /** * process notification that the recipient accepted a share * * @param string $id @@ -771,6 +820,6 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { * @since 14.0.0 */ public function getSupportedShareTypes() { - return ['user']; + return ['user', 'group']; } } |