implement federated group shares

Signed-off-by: Bjoern Schiessle <bjoern@schiessle.org>
This commit is contained in:
Bjoern Schiessle 2018-06-13 14:19:59 +02:00
parent c8631d607e
commit b23032e4c5
No known key found for this signature in database
GPG Key ID: 2378A753E2BF04F6
14 changed files with 274 additions and 113 deletions

View File

@ -47,11 +47,14 @@ class Config {
*
* @param string $resourceType
* @return array
* @throws \OCP\Federation\Exceptions\ProviderDoesNotExistsException
*/
public function getSupportedShareTypes($resourceType) {
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
return $provider->getSupportedShareTypes();
} catch (\Exception $e) {
return [];
}
}
}

View File

@ -35,6 +35,7 @@ use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
use OCP\Federation\ICloudIdManager;
use OCP\IGroupManager;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IURLGenerator;
@ -57,6 +58,9 @@ class RequestHandlerController extends Controller {
/** @var IUserManager */
private $userManager;
/** @var IGroupManager */
private $groupManager;
/** @var IURLGenerator */
private $urlGenerator;
@ -76,6 +80,7 @@ class RequestHandlerController extends Controller {
IRequest $request,
ILogger $logger,
IUserManager $userManager,
IGroupManager $groupManager,
IURLGenerator $urlGenerator,
ICloudFederationProviderManager $cloudFederationProviderManager,
Config $config,
@ -86,6 +91,7 @@ class RequestHandlerController extends Controller {
$this->logger = $logger;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->urlGenerator = $urlGenerator;
$this->cloudFederationProviderManager = $cloudFederationProviderManager;
$this->config = $config;
@ -136,9 +142,19 @@ class RequestHandlerController extends Controller {
);
}
$supportedShareTypes = $this->config->getSupportedShareTypes($resourceType);
if (!in_array($shareType, $supportedShareTypes)) {
return new JSONResponse(
['message' => 'Share type "' . $shareType . '" not implemented'],
Http::STATUS_NOT_IMPLEMENTED
);
}
$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
$shareWithLocalId = $cloudId->getUser();
$shareWith = $this->mapUid($shareWithLocalId);
$shareWith = $cloudId->getUser();
if ($shareType === 'user') {
$shareWith = $this->mapUid($shareWith);
if (!$this->userManager->userExists($shareWith)) {
return new JSONResponse(
@ -146,6 +162,16 @@ class RequestHandlerController extends Controller {
Http::STATUS_BAD_REQUEST
);
}
}
if ($shareType === 'group') {
if(!$this->groupManager->groupExists($shareWith)) {
return new JSONResponse(
['message' => 'Group "' . $shareWith . '" does not exists at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST
);
}
}
// if no explicit display name is given, we use the uid as display name
$ownerDisplayName = $ownerDisplayName === null ? $owner : $ownerDisplayName;
@ -161,7 +187,7 @@ class RequestHandlerController extends Controller {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
$share = $this->factory->getCloudFederationShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType);
$share->setProtocol($protocol);
$id = $provider->shareReceived($share);
$provider->shareReceived($share);
} catch (ProviderDoesNotExistsException $e) {
return new JSONResponse(
['message' => $e->getMessage()],
@ -179,7 +205,7 @@ class RequestHandlerController extends Controller {
);
}
$user = $this->userManager->get($shareWithLocalId);
$user = $this->userManager->get($shareWith);
$recipientDisplayName = '';
if($user) {
$recipientDisplayName = $user->getDisplayName();
@ -259,7 +285,6 @@ class RequestHandlerController extends Controller {
* @return string mixed
*/
private function mapUid($uid) {
\OC::$server->getURLGenerator()->linkToDocs('key');
// FIXME this should be a method in the user management instead
$this->logger->debug('shareWith before, ' . $uid, ['app' => $this->appName]);
\OCP\Util::emitHook(

View File

@ -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()
);
}

View File

@ -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();

View File

@ -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'
]
);

View File

@ -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,6 +199,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
}
// FIXME this should be a method in the user management instead
if ($shareType === Share::SHARE_TYPE_USER) {
$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
Util::emitHook(
'\OCA\Files_Sharing\API\Server2Server',
@ -203,6 +213,11 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
}
\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, [
@ -297,6 +301,51 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
throw new BadRequestException([$notificationType]);
}
/**
* 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
*
@ -771,6 +820,6 @@ class CloudFederationProviderFiles implements ICloudFederationProvider {
* @since 14.0.0
*/
public function getSupportedShareTypes() {
return ['user'];
return ['user', 'group'];
}
}

View File

@ -15,6 +15,17 @@
<autoincrement>1</autoincrement>
<length>4</length>
</field>
<field>
<name>parent</name>
<type>integer</type>
<default>-1</default>
<length>4</length>
</field>
<field>
<name>share_type</name>
<type>integer</type>
<length>4</length>
</field>
<field>
<name>remote</name>
<type>text</type>

View File

@ -9,7 +9,7 @@
Turning the feature off removes shared files and folders on the server for all share recipients, and also on the sync clients and mobile apps. More information is available in the Nextcloud Documentation.
</description>
<version>1.6.1</version>
<version>1.6.2</version>
<licence>agpl</licence>
<author>Michael Gapczynski</author>
<author>Bjoern Schiessle</author>

View File

@ -48,6 +48,7 @@ use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\Files\IRootFolder;
use OCP\Lock\LockedException;
use OCP\Share;
use OCP\Share\IManager;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\Exceptions\GenericShareException;
@ -181,15 +182,15 @@ class ShareAPIController extends OCSController {
$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
}
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
if ($share->getShareType() === Share::SHARE_TYPE_USER) {
$sharedWith = $this->userManager->get($share->getSharedWith());
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
} else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
$group = $this->groupManager->get($share->getSharedWith());
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
} else if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
$result['share_with'] = $share->getPassword();
$result['share_with_displayname'] = $share->getPassword();
@ -197,16 +198,16 @@ class ShareAPIController extends OCSController {
$result['token'] = $share->getToken();
$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
} else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() || Share::SHARE_TYPE_REMOTE_GROUP) {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
$result['token'] = $share->getToken();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
} else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
$result['share_with'] = $share->getSharedWith();
$result['password'] = $share->getPassword();
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
$result['token'] = $share->getToken();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
} else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
// getSharedWith() returns either "name (type, owner)" or
// "name (type, owner) [id]", depending on the Circles app version.
$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
@ -301,7 +302,7 @@ class ShareAPIController extends OCSController {
throw new OCSNotFoundException($this->l->t('Could not delete share'));
}
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP &&
if ($share->getShareType() === Share::SHARE_TYPE_GROUP &&
$share->getShareOwner() !== $this->currentUser &&
$share->getSharedBy() !== $this->currentUser) {
$this->shareManager->deleteFromSelf($share, $this->currentUser);
@ -388,14 +389,14 @@ class ShareAPIController extends OCSController {
$permissions &= ~($permissions & ~$path->getPermissions());
}
if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
if ($shareType === Share::SHARE_TYPE_USER) {
// Valid user is required to share
if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
}
$share->setSharedWith($shareWith);
$share->setPermissions($permissions);
} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
} else if ($shareType === Share::SHARE_TYPE_GROUP) {
if (!$this->shareManager->allowGroupSharing()) {
throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
}
@ -406,7 +407,7 @@ class ShareAPIController extends OCSController {
}
$share->setSharedWith($shareWith);
$share->setPermissions($permissions);
} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
} else if ($shareType === Share::SHARE_TYPE_LINK) {
//Can we even share links?
if (!$this->shareManager->shareApiAllowLinks()) {
throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
@ -416,7 +417,7 @@ class ShareAPIController extends OCSController {
* For now we only allow 1 link share.
* Return the existing link share if this is a duplicate
*/
$existingShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, false, 1, 0);
$existingShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, false, 1, 0);
if (!empty($existingShares)) {
return new DataResponse($this->formatShare($existingShares[0]));
}
@ -457,21 +458,28 @@ class ShareAPIController extends OCSController {
}
}
} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
} else if ($shareType === Share::SHARE_TYPE_REMOTE) {
if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
}
$share->setSharedWith($shareWith);
$share->setPermissions($permissions);
} else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
} else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) {
if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
}
$share->setSharedWith($shareWith);
$share->setPermissions($permissions);
} else if ($shareType === Share::SHARE_TYPE_EMAIL) {
if ($share->getNodeType() === 'file') {
$share->setPermissions(Constants::PERMISSION_READ);
} else {
$share->setPermissions($permissions);
}
$share->setSharedWith($shareWith);
} else if ($shareType === \OCP\Share::SHARE_TYPE_CIRCLE) {
} else if ($shareType === Share::SHARE_TYPE_CIRCLE) {
if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
}
@ -512,9 +520,9 @@ class ShareAPIController extends OCSController {
*/
private function getSharedWithMe($node = null, bool $includeTags): DataResponse {
$userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
$groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
$circleShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
$userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
$groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
$circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
$shares = array_merge($userShares, $groupShares, $circleShares);
@ -554,14 +562,14 @@ class ShareAPIController extends OCSController {
/** @var \OCP\Share\IShare[] $shares */
$shares = [];
foreach ($nodes as $node) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
if($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $node, false, -1, 0));
if($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $node, false, -1, 0));
}
if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
}
}
@ -635,16 +643,16 @@ class ShareAPIController extends OCSController {
}
// Get all shares
$userShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
$groupShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
$linkShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
$mailShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
$userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
$groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
$linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
$mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
} else {
$mailShares = [];
}
if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
$circleShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
$circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
} else {
$circleShares = [];
}
@ -652,7 +660,12 @@ class ShareAPIController extends OCSController {
$shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares);
if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
$federatedShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
$shares = array_merge($shares, $federatedShares);
}
if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
$shares = array_merge($shares, $federatedShares);
}
@ -711,7 +724,7 @@ class ShareAPIController extends OCSController {
/*
* expirationdate, password and publicUpload only make sense for link shares
*/
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
$newPermissions = null;
if ($publicUpload === 'true') {
@ -783,7 +796,7 @@ class ShareAPIController extends OCSController {
$share->setPermissions($permissions);
}
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
if ($password === '') {
$share->setPassword(null);
} else if ($password !== null) {
@ -806,8 +819,8 @@ class ShareAPIController extends OCSController {
if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) {
/* Check if this is an incomming share */
$incomingShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
$incomingShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
/** @var \OCP\Share\IShare[] $incomingShares */
if (!empty($incomingShares)) {
@ -846,13 +859,13 @@ class ShareAPIController extends OCSController {
}
// If the share is shared with you (or a group you are a member of)
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
if ($share->getShareType() === Share::SHARE_TYPE_USER &&
$share->getSharedWith() === $this->currentUser
) {
return true;
}
if ($checkGroups && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) {
$sharedWith = $this->groupManager->get($share->getSharedWith());
$user = $this->userManager->get($this->currentUser);
if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
@ -860,7 +873,7 @@ class ShareAPIController extends OCSController {
}
}
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
// TODO: have a sanity check like above?
return true;
}
@ -915,7 +928,7 @@ class ShareAPIController extends OCSController {
try {
if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
return $share;
}
@ -924,7 +937,7 @@ class ShareAPIController extends OCSController {
}
try {
if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
return $share;
}

View File

@ -126,12 +126,15 @@ class Manager {
* @param string $password
* @param string $name
* @param string $owner
* @param int $shareType
* @param boolean $accepted
* @param string $user
* @param int $remoteId
* @param int $parent
* @return Mount|null
* @throws \Doctrine\DBAL\DBALException
*/
public function addShare($remote, $token, $password, $name, $owner, $accepted=false, $user = null, $remoteId = -1) {
public function addShare($remote, $token, $password, $name, $owner, $shareType, $accepted=false, $user = null, $remoteId = -1, $parent = -1) {
$user = $user ? $user : $this->uid;
$accepted = $accepted ? 1 : 0;
@ -156,6 +159,7 @@ class Manager {
'mountpoint_hash' => $hash,
'accepted' => $accepted,
'remote_id' => $remoteId,
'share_type' => $shareType,
];
$i = 1;
@ -174,10 +178,10 @@ class Manager {
$query = $this->connection->prepare('
INSERT INTO `*PREFIX*share_external`
(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`, `parent`, `share_type`)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
');
$query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId));
$query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId, $parent, $shareType));
$options = array(
'remote' => $remote,
@ -223,6 +227,7 @@ class Manager {
$mountPoint = Filesystem::normalizePath($mountPoint);
$hash = md5($mountPoint);
if($share['share_type'] === \OCP\Share::SHARE_TYPE_USER) {
$acceptShare = $this->connection->prepare('
UPDATE `*PREFIX*share_external`
SET `accepted` = ?,
@ -230,6 +235,9 @@ class Manager {
`mountpoint_hash` = ?
WHERE `id` = ? AND `user` = ?');
$updated = $acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid));
} else {
// TODO group share, add additional row for the user who accepted it
}
if ($updated === true) {
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept');
\OC_Hook::emit(Share::class, 'federated_share_added', ['server' => $share['remote']]);
@ -537,10 +545,17 @@ class Manager {
* @return array list of open server-to-server shares
*/
private function getShares($accepted) {
$user = $this->userManager->get($this->uid);
$groups = $this->groupManager->getUserGroups($user);
$userGroups = [];
foreach ($groups as $group) {
$userGroups[] = $group->getGID();
}
$query = 'SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`
FROM `*PREFIX*share_external`
WHERE `user` = ?';
$parameters = [$this->uid];
WHERE `user` = ? OR `user` IN (?)';
$parameters = [$this->uid, implode(',',$userGroups)];
if (!is_null($accepted)) {
$query .= ' AND `accepted` = ?';
$parameters[] = (int) $accepted;

View File

@ -37,6 +37,7 @@ class Constants {
const SHARE_TYPE_REMOTE = 6;
const SHARE_TYPE_CIRCLE = 7;
const SHARE_TYPE_GUEST = 8;
const SHARE_TYPE_REMOTE_GROUP = 9;
const FORMAT_NONE = -1;
const FORMAT_STATUSES = -2;

View File

@ -226,6 +226,10 @@ class Manager implements IManager {
if ($share->getSharedWith() === null) {
throw new \InvalidArgumentException('SharedWith should not be empty');
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE_GROUP) {
if ($share->getSharedWith() === null) {
throw new \InvalidArgumentException('SharedWith should not be empty');
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
if ($share->getSharedWith() === null) {
throw new \InvalidArgumentException('SharedWith should not be empty');
@ -1579,6 +1583,13 @@ class Manager implements IManager {
return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
}
/**
* @inheritdoc
*/
public function outgoingServer2ServerGroupSharesAllowed() {
return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
}
/**
* @inheritdoc
*/

View File

@ -135,7 +135,8 @@ class ProviderFactory implements IProviderFactory {
$this->serverContainer->getConfig(),
$this->serverContainer->getUserManager(),
$this->serverContainer->getCloudIdManager(),
$this->serverContainer->getGlobalScaleConfig()
$this->serverContainer->getGlobalScaleConfig(),
$this->serverContainer->getCloudFederationProviderManager()
);
}
@ -250,7 +251,7 @@ class ProviderFactory implements IProviderFactory {
$shareType === \OCP\Share::SHARE_TYPE_LINK
) {
$provider = $this->defaultShareProvider();
} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE || \OCP\Share::SHARE_TYPE_REMOTE_GROUP) {
$provider = $this->federatedShareProvider();
} else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
$provider = $this->getShareByMailProvider();

View File

@ -369,6 +369,14 @@ interface IManager {
*/
public function outgoingServer2ServerSharesAllowed();
/**
* Check if outgoing server2server shares are allowed
* @return bool
* @since 14.0.0
*/
public function outgoingServer2ServerGroupSharesAllowed();
/**
* Check if a given share provider exists
* @param int $shareType