浏览代码

Inherited Shares

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
working on users with resharing rights

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
-getLogger()

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
cleaning

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
fix type

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Update SharingRightsException.php
tags/v18.0.0beta1
Maxence Lange 5 年前
父节点
当前提交
5794f14df9
没有帐户链接到提交者的电子邮件

+ 5
- 0
apps/files_sharing/appinfo/routes.php 查看文件

@@ -53,6 +53,11 @@ return [
'url' => '/api/v1/shares',
'verb' => 'GET',
],
[
'name' => 'ShareAPI#getInheritedShares',
'url' => '/api/v1/shares/inherited',
'verb' => 'GET',
],
[
'name' => 'ShareAPI#createShare',
'url' => '/api/v1/shares',

+ 1
- 0
apps/files_sharing/composer/composer/autoload_classmap.php 查看文件

@@ -34,6 +34,7 @@ return array(
'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => $baseDir . '/../lib/DeleteOrphanedSharesJob.php',
'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => $baseDir . '/../lib/Exceptions/BrokenPath.php',
'OCA\\Files_Sharing\\Exceptions\\S2SException' => $baseDir . '/../lib/Exceptions/S2SException.php',
'OCA\\Files_Sharing\\Exceptions\\SharingRightsException' => $baseDir . '/../lib/Exceptions/SharingRightsException.php',
'OCA\\Files_Sharing\\ExpireSharesJob' => $baseDir . '/../lib/ExpireSharesJob.php',
'OCA\\Files_Sharing\\External\\Cache' => $baseDir . '/../lib/External/Cache.php',
'OCA\\Files_Sharing\\External\\Manager' => $baseDir . '/../lib/External/Manager.php',

+ 1
- 0
apps/files_sharing/composer/composer/autoload_static.php 查看文件

@@ -49,6 +49,7 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => __DIR__ . '/..' . '/../lib/DeleteOrphanedSharesJob.php',
'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => __DIR__ . '/..' . '/../lib/Exceptions/BrokenPath.php',
'OCA\\Files_Sharing\\Exceptions\\S2SException' => __DIR__ . '/..' . '/../lib/Exceptions/S2SException.php',
'OCA\\Files_Sharing\\Exceptions\\SharingRightsException' => __DIR__ . '/..' . '/../lib/Exceptions/SharingRightsException.php',
'OCA\\Files_Sharing\\ExpireSharesJob' => __DIR__ . '/..' . '/../lib/ExpireSharesJob.php',
'OCA\\Files_Sharing\\External\\Cache' => __DIR__ . '/..' . '/../lib/External/Cache.php',
'OCA\\Files_Sharing\\External\\Manager' => __DIR__ . '/..' . '/../lib/External/Manager.php',

+ 271
- 49
apps/files_sharing/lib/Controller/ShareAPIController.php 查看文件

@@ -12,6 +12,7 @@ declare(strict_types=1);
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Vincent Petry <pvince81@owncloud.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Maxence Lange <maxence@artificial-owl.com>
*
* @license AGPL-3.0
*
@@ -31,6 +32,8 @@ declare(strict_types=1);

namespace OCA\Files_Sharing\Controller;

use OCA\Files_Sharing\Exceptions\SharingRightsException;
use OCA\Files_Sharing\External\Storage;
use OCA\Files\Helper;
use OCA\Files_Sharing\External\Storage;
use OCP\App\IAppManager;
@@ -42,6 +45,7 @@ use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\QueryException;
use OCP\Constants;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
@@ -383,7 +387,7 @@ class ShareAPIController extends OCSController {
* @throws OCSException
* @throws OCSForbiddenException
* @throws OCSNotFoundException
* @throws \OCP\Files\InvalidPathException
* @throws InvalidPathException
* @suppress PhanUndeclaredClassMethod
*/
public function createShare(
@@ -579,11 +583,12 @@ class ShareAPIController extends OCSController {
}

/**
* @param \OCP\Files\File|\OCP\Files\Folder $node
* @param null|Node $node
* @param boolean $includeTags
* @return DataResponse
*
* @return array
*/
private function getSharedWithMe($node = null, bool $includeTags): DataResponse {
private function getSharedWithMe($node, bool $includeTags): array {

$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);
@@ -592,7 +597,7 @@ class ShareAPIController extends OCSController {

$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);

$shares = array_filter($shares, function (IShare $share) {
$shares = array_filter($shares, function(IShare $share) {
return $share->getShareOwner() !== $this->currentUser;
});

@@ -611,13 +616,15 @@ class ShareAPIController extends OCSController {
$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
}

return new DataResponse($formatted);
return $formatted;
}

/**
* @param \OCP\Files\Folder $folder
* @param \OCP\Files\Node $folder
*
* @return array
* @throws OCSBadRequestException
* @throws NotFoundException
*/
private function getSharesInDir(Node $folder): array {
if (!($folder instanceof \OCP\Files\Folder)) {
@@ -638,15 +645,35 @@ class ShareAPIController extends OCSController {
if (in_array($share->getId(), $known)) {
return false;
}
$known[] = $share->getId();
return true;
});

try {
$format = $this->formatShare($share);

$known[] = $share->getId();
$formatted[] = $format;
if ($share->getSharedBy() === $this->currentUser) {
$miniFormatted[] = $format;
}
if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
$resharingRight = true;
}
} catch (\Exception $e) {
//Ignore this share
}
}

if (!$resharingRight) {
$formatted = $miniFormatted;
}

return $formatted;
}

/**
* The getShares function.
*
* @NoAdminRequired
* @NoCSRFRequired
*
* @param string $shared_with_me
* @param string $reshares
@@ -659,64 +686,82 @@ class ShareAPIController extends OCSController {
* - Get shares for a specific path (?path=...)
* - Get all shares in a folder (?subfiles=true&path=..)
*
* @param string $include_tags
*
* @return DataResponse
* @throws NotFoundException
* @throws OCSBadRequestException
* @throws OCSNotFoundException
*/
public function getShares(
string $shared_with_me = 'false',
string $reshares = 'false',
string $subfiles = 'false',
string $path = null,
string $path = '',
string $include_tags = 'false'
): DataResponse {

if ($path !== null) {
$node = null;
if ($path !== '') {
$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
try {
$path = $userFolder->get($path);
$this->lock($path);
} catch (\OCP\Files\NotFoundException $e) {
throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
$node = $userFolder->get($path);
$this->lock($node);
} catch (NotFoundException $e) {
throw new OCSNotFoundException(
$this->l->t('Wrong path, file/folder doesn\'t exist')
);
} catch (LockedException $e) {
throw new OCSNotFoundException($this->l->t('Could not lock path'));
throw new OCSNotFoundException($this->l->t('Could not lock node'));
}
}

$include_tags = $include_tags === 'true';
$shares = $this->getFormattedShares(
$this->currentUser,
$node,
($shared_with_me === 'true'),
($reshares === 'true'),
($subfiles === 'true'),
($include_tags === 'true')
);

if ($shared_with_me === 'true') {
$result = $this->getSharedWithMe($path, $include_tags);
return $result;
}
return new DataResponse($shares);
}

if ($reshares === 'true') {
$reshares = true;
} else {
$reshares = false;

/**
* @param string $viewer
* @param Node $node
* @param bool $sharedWithMe
* @param bool $reShares
* @param bool $subFiles
* @param bool $includeTags
*
* @return array
* @throws NotFoundException
* @throws OCSBadRequestException
*/
private function getFormattedShares(
string $viewer, $node = null, bool $sharedWithMe = false, bool $reShares = false,
bool $subFiles = false, bool $includeTags = false
): array {

if ($sharedWithMe) {
return $this->getSharedWithMe($node, $includeTags);
}

if ($subfiles === 'true') {
$shares = $this->getSharesInDir($path);
$recipientNode = null;
} else {
// get all shares
$shares = $this->getAllShares($path, $reshares);
$recipientNode = $path;
if ($subFiles) {
return $this->getSharesInDir($node);
}

// process all shares
$shares = $this->getSharesFromNode($viewer, $node, $reShares);

$formatted = $miniFormatted = [];
$resharingRight = false;
foreach ($shares as $share) {
/** @var IShare $share */

// do not list the shares of the current user
if ($share->getSharedWith() === $this->currentUser) {
continue;
}

try {
$format = $this->formatShare($share, $recipientNode);
/** @var IShare $share */
$format = $this->formatShare($share, $node);
$formatted[] = $format;

// let's also build a list of shares created
@@ -731,8 +776,7 @@ class ShareAPIController extends OCSController {
if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $path)) {
$resharingRight = true;
}
} catch (\Exception $e) {
//Ignore share
} catch (InvalidPathException | NotFoundException $e) {
}
}

@@ -740,13 +784,89 @@ class ShareAPIController extends OCSController {
$formatted = $miniFormatted;
}

if ($include_tags) {
$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
if ($includeTags) {
$formatted =
Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
}

return new DataResponse($formatted);
return $formatted;
}


/**
* The getInheritedShares function.
* returns all shares relative to a file, including parent folders shares rights.
*
* @NoAdminRequired
*
* @param string $path
*
* - Get shares by the current user
* - Get shares by the current user and reshares (?reshares=true)
* - Get shares with the current user (?shared_with_me=true)
* - Get shares for a specific path (?path=...)
* - Get all shares in a folder (?subfiles=true&path=..)
*
* @return DataResponse
* @throws InvalidPathException
* @throws NotFoundException
* @throws OCSNotFoundException
* @throws OCSBadRequestException
* @throws SharingRightsException
*/
public function getInheritedShares(string $path): DataResponse {

// get Node from (string) path.
$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
try {
$node = $userFolder->get($path);
$this->lock($node);
} catch (\OCP\Files\NotFoundException $e) {
throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
} catch (LockedException $e) {
throw new OCSNotFoundException($this->l->t('Could not lock path'));
}

// current User has resharing rights ?
$this->confirmSharingRights($node);

// initiate real owner.
$owner = $node->getOwner()
->getUID();
if (!$this->userManager->userExists($owner)) {
return new DataResponse([]);
}

// get node based on the owner, fix owner in case of external storage
$userFolder = $this->rootFolder->getUserFolder($owner);
if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
$owner = $node->getOwner()
->getUID();
$userFolder = $this->rootFolder->getUserFolder($owner);
$nodes = $userFolder->getById($node->getId());
$node = array_shift($nodes);
}
$basePath = $userFolder->getPath();

// generate node list for each parent folders
/** @var Node[] $nodes */
$nodes = [];
while ($node->getPath() !== $basePath) {
$nodes[] = $node;
$node = $node->getParent();
}

// for each nodes, retrieve shares.
$shares = [];
foreach ($nodes as $node) {
$getShares = $this->getFormattedShares($owner, $node, false, true);
$this->mergeFormattedShares($shares, $getShares);
}

return new DataResponse(array_values($shares));
}


/**
* @NoAdminRequired
*
@@ -1261,6 +1381,90 @@ class ShareAPIController extends OCSController {
}


/**
* @param string $viewer
* @param Node $node
* @param bool $reShares
*
* @return IShare[]
*/
private function getSharesFromNode(string $viewer, $node, bool $reShares): array {

$providers = [
Share::SHARE_TYPE_USER,
Share::SHARE_TYPE_GROUP,
Share::SHARE_TYPE_LINK,
Share::SHARE_TYPE_EMAIL,
Share::SHARE_TYPE_EMAIL,
Share::SHARE_TYPE_CIRCLE,
Share::SHARE_TYPE_ROOM
];

// Should we assume that the (currentUser) viewer is the owner of the node !?
$shares = [];
foreach ($providers as $provider) {
if (!$this->shareManager->shareProviderExists($provider)) {
continue;
}

$providerShares =
$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
$shares = array_merge($shares, $providerShares);
}

if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
$federatedShares = $this->shareManager->getSharesBy(
$this->currentUser, Share::SHARE_TYPE_REMOTE, $node, $reShares, -1, 0
);
$shares = array_merge($shares, $federatedShares);
}

if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
$federatedShares = $this->shareManager->getSharesBy(
$this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
);
$shares = array_merge($shares, $federatedShares);
}

return $shares;
}


/**
* @param Node $node
*
* @throws SharingRightsException
*/
private function confirmSharingRights(Node $node): void {
if (!$this->hasResharingRights($this->currentUser, $node)) {
throw new SharingRightsException('no sharing rights on this item');
}
}


/**
* @param string $viewer
* @param Node $node
*
* @return bool
*/
private function hasResharingRights($viewer, $node): bool {
foreach ([$node, $node->getParent()] as $node) {
$shares = $this->getSharesFromNode($viewer, $node, true);
foreach ($shares as $share) {
try {
if ($this->shareProviderResharingRights($viewer, $share, $node)) {
return true;
}
} catch (InvalidPathException | NotFoundException $e) {
}
}
}

return false;
}


/**
* Returns if we can find resharing rights in an IShare object for a specific user.
*
@@ -1269,9 +1473,10 @@ class ShareAPIController extends OCSController {
* @param string $userId
* @param IShare $share
* @param Node $node
*
* @return bool
* @throws NotFoundException
* @throws \OCP\Files\InvalidPathException
* @throws InvalidPathException
*/
private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {

@@ -1280,7 +1485,7 @@ class ShareAPIController extends OCSController {
}

// we check that current user have parent resharing rights on the current file
if ($node !== null && ($node->getPermissions() & \OCP\Constants::PERMISSION_SHARE) !== 0) {
if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
return true;
}

@@ -1357,4 +1562,21 @@ class ShareAPIController extends OCSController {
return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $federatedShares, $federatedGroupShares);
}


/**
* merging already formatted shares.
* We'll make an associative array to easily detect duplicate Ids.
* Keys _needs_ to be removed after all shares are retrieved and merged.
*
* @param array $shares
* @param array $newShares
*/
private function mergeFormattedShares(array &$shares, array $newShares) {
foreach ($newShares as $newShare) {
if (!array_key_exists($newShare['id'], $shares)) {
$shares[$newShare['id']] = $newShare;
}
}
}

}

+ 40
- 0
apps/files_sharing/lib/Exceptions/SharingRightsException.php 查看文件

@@ -0,0 +1,40 @@
<?php

/**
* @copyright Copyright (c) 2019, Maxence Lange <maxence@artificial-owl.com>
*
* @author Maxence Lange <maxence@artificial-owl.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Files_Sharing\Exceptions;

use Exception;


/**
* Sharing and Resharing rights.
*
* Class SharingRightsException
*
* @package OCA\Files_Sharing\Exceptions
*/
class SharingRightsException extends Exception {

}


正在加载...
取消
保存