Merge pull request #23918 from owncloud/cruds-for-federated-shares

bring back CRUDS permissions for federated shares
This commit is contained in:
Björn Schießle 2016-04-22 14:50:42 +02:00
commit 606b756a94
8 changed files with 136 additions and 78 deletions

View File

@ -246,6 +246,8 @@ class FilesPlugin extends ServerPlugin {
*/ */
public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) { public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
$httpRequest = $this->server->httpRequest;
if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
$propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) { $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
@ -265,8 +267,10 @@ class FilesPlugin extends ServerPlugin {
return $perms; return $perms;
}); });
$propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node) { $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
return $node->getSharePermissions(); return $node->getSharePermissions(
$httpRequest->getRawServerValue('PHP_AUTH_USER')
);
}); });
$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) { $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {

View File

@ -32,6 +32,8 @@ namespace OCA\DAV\Connector\Sabre;
use OC\Files\Mount\MoveableMount; use OC\Files\Mount\MoveableMount;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath; use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
abstract class Node implements \Sabre\DAV\INode { abstract class Node implements \Sabre\DAV\INode {
@ -60,16 +62,27 @@ abstract class Node implements \Sabre\DAV\INode {
*/ */
protected $info; protected $info;
/**
* @var IManager
*/
protected $shareManager;
/** /**
* Sets up the node, expects a full path name * Sets up the node, expects a full path name
* *
* @param \OC\Files\View $view * @param \OC\Files\View $view
* @param \OCP\Files\FileInfo $info * @param \OCP\Files\FileInfo $info
* @param IManager $shareManager
*/ */
public function __construct($view, $info) { public function __construct($view, $info, IManager $shareManager = null) {
$this->fileView = $view; $this->fileView = $view;
$this->path = $this->fileView->getRelativePath($info->getPath()); $this->path = $this->fileView->getRelativePath($info->getPath());
$this->info = $info; $this->info = $info;
if ($shareManager) {
$this->shareManager = $shareManager;
} else {
$this->shareManager = \OC::$server->getShareManager();
}
} }
protected function refreshInfo() { protected function refreshInfo() {
@ -215,9 +228,21 @@ abstract class Node implements \Sabre\DAV\INode {
} }
/** /**
* @param string $user
* @return int * @return int
*/ */
public function getSharePermissions() { public function getSharePermissions($user) {
// check of we access a federated share
if ($user !== null) {
try {
$share = $this->shareManager->getShareByToken($user);
return $share->getPermissions();
} catch (ShareNotFound $e) {
// ignore
}
}
$storage = $this->info->getStorage(); $storage = $this->info->getStorage();
$path = $this->info->getInternalPath(); $path = $this->info->getInternalPath();

View File

@ -23,6 +23,12 @@
namespace OCA\DAV\Tests\Unit\Connector\Sabre; namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Class Node
*
* @group DB
* @package OCA\DAV\Tests\Unit\Connector\Sabre
*/
class Node extends \Test\TestCase { class Node extends \Test\TestCase {
public function davPermissionsProvider() { public function davPermissionsProvider() {
return array( return array(
@ -66,52 +72,64 @@ class Node extends \Test\TestCase {
public function sharePermissionsProvider() { public function sharePermissionsProvider() {
return [ return [
[\OCP\Files\FileInfo::TYPE_FILE, 1, 1], [\OCP\Files\FileInfo::TYPE_FILE, null, 1, 1],
[\OCP\Files\FileInfo::TYPE_FILE, 3, 3], [\OCP\Files\FileInfo::TYPE_FILE, null, 3, 3],
[\OCP\Files\FileInfo::TYPE_FILE, 5, 1], [\OCP\Files\FileInfo::TYPE_FILE, null, 5, 1],
[\OCP\Files\FileInfo::TYPE_FILE, 7, 3], [\OCP\Files\FileInfo::TYPE_FILE, null, 7, 3],
[\OCP\Files\FileInfo::TYPE_FILE, 9, 1], [\OCP\Files\FileInfo::TYPE_FILE, null, 9, 1],
[\OCP\Files\FileInfo::TYPE_FILE, 11, 3], [\OCP\Files\FileInfo::TYPE_FILE, null, 11, 3],
[\OCP\Files\FileInfo::TYPE_FILE, 13, 1], [\OCP\Files\FileInfo::TYPE_FILE, null, 13, 1],
[\OCP\Files\FileInfo::TYPE_FILE, 15, 3], [\OCP\Files\FileInfo::TYPE_FILE, null, 15, 3],
[\OCP\Files\FileInfo::TYPE_FILE, 17, 17], [\OCP\Files\FileInfo::TYPE_FILE, null, 17, 17],
[\OCP\Files\FileInfo::TYPE_FILE, 19, 19], [\OCP\Files\FileInfo::TYPE_FILE, null, 19, 19],
[\OCP\Files\FileInfo::TYPE_FILE, 21, 17], [\OCP\Files\FileInfo::TYPE_FILE, null, 21, 17],
[\OCP\Files\FileInfo::TYPE_FILE, 23, 19], [\OCP\Files\FileInfo::TYPE_FILE, null, 23, 19],
[\OCP\Files\FileInfo::TYPE_FILE, 25, 17], [\OCP\Files\FileInfo::TYPE_FILE, null, 25, 17],
[\OCP\Files\FileInfo::TYPE_FILE, 27, 19], [\OCP\Files\FileInfo::TYPE_FILE, null, 27, 19],
[\OCP\Files\FileInfo::TYPE_FILE, 29, 17], [\OCP\Files\FileInfo::TYPE_FILE, null, 29, 17],
[\OCP\Files\FileInfo::TYPE_FILE, 30, 18], [\OCP\Files\FileInfo::TYPE_FILE, null, 30, 18],
[\OCP\Files\FileInfo::TYPE_FILE, 31, 19], [\OCP\Files\FileInfo::TYPE_FILE, null, 31, 19],
[\OCP\Files\FileInfo::TYPE_FOLDER, 1, 1], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 1, 1],
[\OCP\Files\FileInfo::TYPE_FOLDER, 3, 3], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 3, 3],
[\OCP\Files\FileInfo::TYPE_FOLDER, 5, 5], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 5, 5],
[\OCP\Files\FileInfo::TYPE_FOLDER, 7, 7], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 7, 7],
[\OCP\Files\FileInfo::TYPE_FOLDER, 9, 9], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 9, 9],
[\OCP\Files\FileInfo::TYPE_FOLDER, 11, 11], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 11, 11],
[\OCP\Files\FileInfo::TYPE_FOLDER, 13, 13], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 13, 13],
[\OCP\Files\FileInfo::TYPE_FOLDER, 15, 15], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 15, 15],
[\OCP\Files\FileInfo::TYPE_FOLDER, 17, 17], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 17, 17],
[\OCP\Files\FileInfo::TYPE_FOLDER, 19, 19], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 19, 19],
[\OCP\Files\FileInfo::TYPE_FOLDER, 21, 21], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 21, 21],
[\OCP\Files\FileInfo::TYPE_FOLDER, 23, 23], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 23, 23],
[\OCP\Files\FileInfo::TYPE_FOLDER, 25, 25], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 25, 25],
[\OCP\Files\FileInfo::TYPE_FOLDER, 27, 27], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 27, 27],
[\OCP\Files\FileInfo::TYPE_FOLDER, 29, 29], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 29, 29],
[\OCP\Files\FileInfo::TYPE_FOLDER, 30, 30], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 30, 30],
[\OCP\Files\FileInfo::TYPE_FOLDER, 31, 31], [\OCP\Files\FileInfo::TYPE_FOLDER, null, 31, 31],
[\OCP\Files\FileInfo::TYPE_FOLDER, 'shareToken', 7, 7],
]; ];
} }
/** /**
* @dataProvider sharePermissionsProvider * @dataProvider sharePermissionsProvider
*/ */
public function testSharePermissions($type, $permissions, $expected) { public function testSharePermissions($type, $user, $permissions, $expected) {
$storage = $this->getMock('\OCP\Files\Storage'); $storage = $this->getMock('\OCP\Files\Storage');
$storage->method('getPermissions')->willReturn($permissions); $storage->method('getPermissions')->willReturn($permissions);
$mountpoint = $this->getMock('\OCP\Files\Mount\IMountPoint'); $mountpoint = $this->getMock('\OCP\Files\Mount\IMountPoint');
$mountpoint->method('getMountPoint')->willReturn('myPath'); $mountpoint->method('getMountPoint')->willReturn('myPath');
$shareManager = $this->getMockBuilder('OCP\Share\IManager')->disableOriginalConstructor()->getMock();
$share = $this->getMockBuilder('OCP\Share\IShare')->disableOriginalConstructor()->getMock();
if ($user === null) {
$shareManager->expects($this->never())->method('getShareByToken');
$share->expects($this->never())->method('getPermissions');
} else {
$shareManager->expects($this->once())->method('getShareByToken')->with($user)
->willReturn($share);
$share->expects($this->once())->method('getPermissions')->willReturn($permissions);
}
$info = $this->getMockBuilder('\OC\Files\FileInfo') $info = $this->getMockBuilder('\OC\Files\FileInfo')
->disableOriginalConstructor() ->disableOriginalConstructor()
@ -125,6 +143,7 @@ class Node extends \Test\TestCase {
$view = $this->getMock('\OC\Files\View'); $view = $this->getMock('\OC\Files\View');
$node = new \OCA\DAV\Connector\Sabre\File($view, $info); $node = new \OCA\DAV\Connector\Sabre\File($view, $info);
$this->assertEquals($expected, $node->getSharePermissions()); $this->invokePrivate($node, 'shareManager', [$shareManager]);
$this->assertEquals($expected, $node->getSharePermissions($user));
} }
} }

View File

@ -62,20 +62,25 @@ if (!$isWritable) {
$rootInfo = \OC\Files\Filesystem::getFileInfo($path); $rootInfo = \OC\Files\Filesystem::getFileInfo($path);
$rootView = new \OC\Files\View(''); $rootView = new \OC\Files\View('');
$shareManager = \OC::$server->getShareManager();
$share = $shareManager->getShareByToken($token);
$sharePermissions= (int)$share->getPermissions();
/** /**
* @param \OCP\Files\FileInfo $dir * @param \OCP\Files\FileInfo $dir
* @param \OC\Files\View $view * @param \OC\Files\View $view
* @return array * @return array
*/ */
function getChildInfo($dir, $view) { function getChildInfo($dir, $view, $sharePermissions) {
$children = $view->getDirectoryContent($dir->getPath()); $children = $view->getDirectoryContent($dir->getPath());
$result = array(); $result = array();
foreach ($children as $child) { foreach ($children as $child) {
$formatted = \OCA\Files\Helper::formatFileInfo($child); $formatted = \OCA\Files\Helper::formatFileInfo($child);
if ($child->getType() === 'dir') { if ($child->getType() === 'dir') {
$formatted['children'] = getChildInfo($child, $view); $formatted['children'] = getChildInfo($child, $view, $sharePermissions);
} }
$formatted['mtime'] = $formatted['mtime'] / 1000; $formatted['mtime'] = $formatted['mtime'] / 1000;
$formatted['permissions'] = $sharePermissions & (int)$formatted['permissions'];
$result[] = $formatted; $result[] = $formatted;
} }
return $result; return $result;
@ -83,8 +88,11 @@ function getChildInfo($dir, $view) {
$result = \OCA\Files\Helper::formatFileInfo($rootInfo); $result = \OCA\Files\Helper::formatFileInfo($rootInfo);
$result['mtime'] = $result['mtime'] / 1000; $result['mtime'] = $result['mtime'] / 1000;
$result['permissions'] = (int)$result['permissions'] & $sharePermissions;
if ($rootInfo->getType() === 'dir') { if ($rootInfo->getType() === 'dir') {
$result['children'] = getChildInfo($rootInfo, $rootView); $result['children'] = getChildInfo($rootInfo, $rootView, $sharePermissions);
} }
OCP\JSON::success(array('data' => $result)); OCP\JSON::success(array('data' => $result));

View File

@ -320,4 +320,20 @@ class Storage extends DAV implements ISharedStorage {
return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE); return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
} }
public function getPermissions($path) {
$response = $this->propfind($path);
if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
$permissions = $response['{http://open-collaboration-services.org/ns}share-permissions'];
} else {
// use default permission if remote server doesn't provide the share permissions
if ($this->is_dir($path)) {
$permissions = \OCP\Constants::PERMISSION_ALL;
} else {
$permissions = \OCP\Constants::PERMISSION_ALL & ~\OCP\Constants::PERMISSION_CREATE;
}
}
return $permissions;
}
} }

View File

@ -28,22 +28,19 @@
'<label for="mail-{{cid}}-{{shareWith}}">{{notifyByMailLabel}}</label>' + '<label for="mail-{{cid}}-{{shareWith}}">{{notifyByMailLabel}}</label>' +
'</span>' + '</span>' +
'{{/unless}} {{/if}}' + '{{/unless}} {{/if}}' +
'{{#if isResharingAllowed}} {{#if sharePermissionPossible}} {{#unless isRemoteShare}}' + '{{#if isResharingAllowed}} {{#if sharePermissionPossible}}' +
'<span class="shareOption">' + '<span class="shareOption">' +
'<input id="canShare-{{cid}}-{{shareWith}}" type="checkbox" name="share" class="permissions checkbox" {{#if hasSharePermission}}checked="checked"{{/if}} data-permissions="{{sharePermission}}" />' + '<input id="canShare-{{cid}}-{{shareWith}}" type="checkbox" name="share" class="permissions checkbox" {{#if hasSharePermission}}checked="checked"{{/if}} data-permissions="{{sharePermission}}" />' +
'<label for="canShare-{{cid}}-{{shareWith}}">{{canShareLabel}}</label>' + '<label for="canShare-{{cid}}-{{shareWith}}">{{canShareLabel}}</label>' +
'</span>' + '</span>' +
'{{/unless}} {{/if}} {{/if}}' + '{{/if}} {{/if}}' +
'{{#if editPermissionPossible}}' + '{{#if editPermissionPossible}}' +
'<span class="shareOption">' + '<span class="shareOption">' +
'<input id="canEdit-{{cid}}-{{shareWith}}" type="checkbox" name="edit" class="permissions checkbox" {{#if hasEditPermission}}checked="checked"{{/if}} />' + '<input id="canEdit-{{cid}}-{{shareWith}}" type="checkbox" name="edit" class="permissions checkbox" {{#if hasEditPermission}}checked="checked"{{/if}} />' +
'<label for="canEdit-{{cid}}-{{shareWith}}">{{canEditLabel}}</label>' + '<label for="canEdit-{{cid}}-{{shareWith}}">{{canEditLabel}}</label>' +
'{{#unless isRemoteShare}}' +
'<a href="#" class="showCruds"><img class="svg" alt="{{crudsLabel}}" src="{{triangleSImage}}"/></a>' + '<a href="#" class="showCruds"><img class="svg" alt="{{crudsLabel}}" src="{{triangleSImage}}"/></a>' +
'{{/unless}}' +
'</span>' + '</span>' +
'{{/if}}' + '{{/if}}' +
'{{#unless isRemoteShare}}' +
'<div class="cruds hidden">' + '<div class="cruds hidden">' +
'{{#if createPermissionPossible}}' + '{{#if createPermissionPossible}}' +
'<span class="shareOption">' + '<span class="shareOption">' +
@ -57,14 +54,13 @@
'<label for="canUpdate-{{cid}}-{{shareWith}}">{{updatePermissionLabel}}</label>' + '<label for="canUpdate-{{cid}}-{{shareWith}}">{{updatePermissionLabel}}</label>' +
'</span>' + '</span>' +
'{{/if}}' + '{{/if}}' +
'{{#if deletePermissionPossible}} {{#unless isRemoteShare}}' + '{{#if deletePermissionPossible}}' +
'<span class="shareOption">' + '<span class="shareOption">' +
'<input id="canDelete-{{cid}}-{{shareWith}}" type="checkbox" name="delete" class="permissions checkbox" {{#if hasDeletePermission}}checked="checked"{{/if}} data-permissions="{{deletePermission}}"/>' + '<input id="canDelete-{{cid}}-{{shareWith}}" type="checkbox" name="delete" class="permissions checkbox" {{#if hasDeletePermission}}checked="checked"{{/if}} data-permissions="{{deletePermission}}"/>' +
'<label for="canDelete-{{cid}}-{{shareWith}}">{{deletePermissionLabel}}</label>' + '<label for="canDelete-{{cid}}-{{shareWith}}">{{deletePermissionLabel}}</label>' +
'</span>' + '</span>' +
'{{/unless}} {{/if}}' + '{{/if}}' +
'</div>' + '</div>' +
'{{/unless}}' +
'</li>' + '</li>' +
'{{/each}}' + '{{/each}}' +
'</ul>' '</ul>'
@ -125,10 +121,6 @@
shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'group') + ')'; shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'group') + ')';
} else if (shareType === OC.Share.SHARE_TYPE_REMOTE) { } else if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'remote') + ')'; shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'remote') + ')';
hasPermissionOverride = {
createPermissionPossible: true,
updatePermissionPossible: true
};
} }
return _.extend(hasPermissionOverride, { return _.extend(hasPermissionOverride, {

View File

@ -154,9 +154,6 @@
// Default permissions are Edit (CRUD) and Share // Default permissions are Edit (CRUD) and Share
// Check if these permissions are possible // Check if these permissions are possible
var permissions = OC.PERMISSION_READ; var permissions = OC.PERMISSION_READ;
if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
permissions = OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_READ;
} else {
if (this.updatePermissionPossible()) { if (this.updatePermissionPossible()) {
permissions = permissions | OC.PERMISSION_UPDATE; permissions = permissions | OC.PERMISSION_UPDATE;
} }
@ -169,7 +166,6 @@
if (this.configModel.get('isResharingAllowed') && (this.sharePermissionPossible())) { if (this.configModel.get('isResharingAllowed') && (this.sharePermissionPossible())) {
permissions = permissions | OC.PERMISSION_SHARE; permissions = permissions | OC.PERMISSION_SHARE;
} }
}
attributes.permissions = permissions; attributes.permissions = permissions;
if (_.isUndefined(attributes.path)) { if (_.isUndefined(attributes.path)) {
@ -411,12 +407,6 @@
if(!_.isObject(share)) { if(!_.isObject(share)) {
throw "Unknown Share"; throw "Unknown Share";
} }
if( share.share_type === OC.Share.SHARE_TYPE_REMOTE
&& ( permission === OC.PERMISSION_SHARE
|| permission === OC.PERMISSION_DELETE))
{
return false;
}
return (share.permissions & permission) === permission; return (share.permissions & permission) === permission;
}, },

View File

@ -246,7 +246,7 @@ class DAV extends Common {
* *
* @throws NotFound * @throws NotFound
*/ */
private function propfind($path) { protected function propfind($path) {
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
$cachedResponse = $this->statCache->get($path); $cachedResponse = $this->statCache->get($path);
if ($cachedResponse === false) { if ($cachedResponse === false) {
@ -264,6 +264,7 @@ class DAV extends Common {
'{DAV:}getcontentlength', '{DAV:}getcontentlength',
'{DAV:}getcontenttype', '{DAV:}getcontenttype',
'{http://owncloud.org/ns}permissions', '{http://owncloud.org/ns}permissions',
'{http://open-collaboration-services.org/ns}share-permissions',
'{DAV:}resourcetype', '{DAV:}resourcetype',
'{DAV:}getetag', '{DAV:}getetag',
) )
@ -741,6 +742,9 @@ class DAV extends Common {
} }
if (!empty($etag) && $cachedData['etag'] !== $etag) { if (!empty($etag) && $cachedData['etag'] !== $etag) {
return true; return true;
} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
return $sharePermissions !== $cachedData['permissions'];
} else if (isset($response['{http://owncloud.org/ns}permissions'])) { } else if (isset($response['{http://owncloud.org/ns}permissions'])) {
$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
return $permissions !== $cachedData['permissions']; return $permissions !== $cachedData['permissions'];