Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions apps/cloud_federation_api/lib/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ public function __construct(ICloudFederationProviderManager $cloudFederationProv
*
* @param string $resourceType
* @return array
* @throws \OCP\Federation\Exceptions\ProviderDoesNotExistsException
*/
public function getSupportedShareTypes($resourceType) {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
return $provider->getSupportedShareTypes();
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
return $provider->getSupportedShareTypes();
} catch (\Exception $e) {
return [];
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
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;
Expand All @@ -57,6 +58,9 @@ class RequestHandlerController extends Controller {
/** @var IUserManager */
private $userManager;

/** @var IGroupManager */
private $groupManager;

/** @var IURLGenerator */
private $urlGenerator;

Expand All @@ -76,6 +80,7 @@ public function __construct($appName,
IRequest $request,
ILogger $logger,
IUserManager $userManager,
IGroupManager $groupManager,
IURLGenerator $urlGenerator,
ICloudFederationProviderManager $cloudFederationProviderManager,
Config $config,
Expand All @@ -86,6 +91,7 @@ public function __construct($appName,

$this->logger = $logger;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->urlGenerator = $urlGenerator;
$this->cloudFederationProviderManager = $cloudFederationProviderManager;
$this->config = $config;
Expand Down Expand Up @@ -136,17 +142,37 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
);
}

$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
$shareWithLocalId = $cloudId->getUser();
$shareWith = $this->mapUid($shareWithLocalId);

if (!$this->userManager->userExists($shareWith)) {
$supportedShareTypes = $this->config->getSupportedShareTypes($resourceType);
if (!in_array($shareType, $supportedShareTypes)) {
return new JSONResponse(
['message' => 'User "' . $shareWith . '" does not exists at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST
['message' => 'Share type "' . $shareType . '" not implemented'],
Http::STATUS_NOT_IMPLEMENTED
);
}

$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
$shareWith = $cloudId->getUser();

if ($shareType === 'user') {
$shareWith = $this->mapUid($shareWith);

if (!$this->userManager->userExists($shareWith)) {
return new JSONResponse(
['message' => 'User "' . $shareWith . '" does not exists at ' . $this->urlGenerator->getBaseUrl()],
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;
$sharedByDisplayName = $sharedByDisplayName === null ? $sharedBy : $sharedByDisplayName;
Expand All @@ -161,7 +187,7 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
$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()],
Expand All @@ -179,7 +205,7 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
);
}

$user = $this->userManager->get($shareWithLocalId);
$user = $this->userManager->get($shareWith);
$recipientDisplayName = '';
if($user) {
$recipientDisplayName = $user->getDisplayName();
Expand Down Expand Up @@ -259,7 +285,6 @@ public function receiveNotification($notificationType, $resourceType, $providerI
* @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(
Expand Down
7 changes: 5 additions & 2 deletions apps/federatedfilesharing/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ function() use ($container) {
$server->getURLGenerator(),
$server->getCloudFederationFactory(),
$server->getCloudFederationProviderManager(),
$server->getDatabaseConnection()
$server->getDatabaseConnection(),
$server->getGroupManager()
);
});

Expand Down Expand Up @@ -145,7 +146,9 @@ protected function initFederatedShareProvider() {
\OC::$server->getConfig(),
\OC::$server->getUserManager(),
\OC::$server->getCloudIdManager(),
$c->query(IConfig::class)
$c->query(IConfig::class),
\OC::$server->getCloudFederationProviderManager()

);
}

Expand Down
89 changes: 75 additions & 14 deletions apps/federatedfilesharing/lib/FederatedShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
namespace OCA\FederatedFileSharing;

use OC\Share20\Share;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudIdManager;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Folder;
Expand Down Expand Up @@ -92,6 +93,12 @@ class FederatedShareProvider implements IShareProvider {
/** @var \OCP\GlobalScale\IConfig */
private $gsConfig;

/** @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.
*
Expand All @@ -106,6 +113,7 @@ class FederatedShareProvider implements IShareProvider {
* @param IUserManager $userManager
* @param ICloudIdManager $cloudIdManager
* @param \OCP\GlobalScale\IConfig $globalScaleConfig
* @param ICloudFederationProviderManager $cloudFederationProviderManager
*/
public function __construct(
IDBConnection $connection,
Expand All @@ -118,7 +126,8 @@ public function __construct(
IConfig $config,
IUserManager $userManager,
ICloudIdManager $cloudIdManager,
\OCP\GlobalScale\IConfig $globalScaleConfig
\OCP\GlobalScale\IConfig $globalScaleConfig,
ICloudFederationProviderManager $cloudFederationProviderManager
) {
$this->dbConnection = $connection;
$this->addressHandler = $addressHandler;
Expand All @@ -131,6 +140,7 @@ public function __construct(
$this->userManager = $userManager;
$this->cloudIdManager = $cloudIdManager;
$this->gsConfig = $globalScaleConfig;
$this->cloudFederationProviderManager = $cloudFederationProviderManager;
}

/**
Expand All @@ -157,12 +167,23 @@ public function create(IShare $share) {
$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']);
Expand Down Expand Up @@ -193,7 +214,7 @@ public function create(IShare $share) {
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
Expand Down Expand Up @@ -238,7 +259,8 @@ protected function createFederatedShare(IShare $share) {
$share->getSharedBy(),
$share->getShareOwner(),
$share->getPermissions(),
$token
$token,
$share->getShareType()
);

$failure = false;
Expand All @@ -258,7 +280,8 @@ protected function createFederatedShare(IShare $share) {
$share->getShareOwner(),
$ownerCloudId->getId(),
$share->getSharedBy(),
$sharedByFederatedId
$sharedByFederatedId,
$share->getShareType()
);

if ($send === false) {
Expand Down Expand Up @@ -342,12 +365,13 @@ protected function getShareFromExternalShareTable(IShare $share) {
* @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))
Expand Down Expand Up @@ -491,7 +515,7 @@ public function getChildren(IShare $parent) {
$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();
Expand Down Expand Up @@ -640,7 +664,7 @@ public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offs
$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.
Expand Down Expand Up @@ -697,7 +721,7 @@ public function getShareById($id, $recipientId = null) {
$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();
Expand Down Expand Up @@ -725,10 +749,11 @@ public function getShareById($id, $recipientId = null) {
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 = [];
Expand Down Expand Up @@ -761,7 +786,7 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
}
$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
Expand Down Expand Up @@ -792,7 +817,7 @@ public function getShareByToken($token) {

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

Expand Down Expand Up @@ -967,6 +992,42 @@ public function isIncomingServer2serverShareEnabled() {
return ($result === 'yes');
}


/**
* check if users from other Nextcloud instances are allowed to send federated group shares
*
* @return bool
*/
public function isOutgoingServer2serverGroupShareEnabled() {
if ($this->gsConfig->onlyInternalFederation()) {
return false;
}
$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
return ($result === 'yes');
}

/**
* check if users are allowed to receive federated group shares
*
* @return bool
*/
public function isIncomingServer2serverGroupShareEnabled() {
if ($this->gsConfig->onlyInternalFederation()) {
return false;
}
$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
return ($result === 'yes');
}

/**
* check if federated group sharing is supported, therefore the OCM API need to be enabled
*
* @return bool
*/
public function isFederatedGroupSharingSupported() {
return $this->cloudFederationProviderManager->isReady();
}

/**
* Check if querying sharees on the lookup server is enabled
*
Expand Down
Loading