summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files_sharing/tests/sharedmount.php214
-rw-r--r--lib/private/share/share.php165
2 files changed, 333 insertions, 46 deletions
diff --git a/apps/files_sharing/tests/sharedmount.php b/apps/files_sharing/tests/sharedmount.php
index 7b256588f93..15ebc7caf71 100644
--- a/apps/files_sharing/tests/sharedmount.php
+++ b/apps/files_sharing/tests/sharedmount.php
@@ -237,6 +237,220 @@ class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase {
);
}
+ function dataPermissionMovedGroupShare() {
+ $data = [];
+
+ $powerset = function($permissions) {
+ $results = [\OCP\Constants::PERMISSION_READ];
+
+ foreach ($permissions as $permission) {
+ foreach ($results as $combination) {
+ $results[] = $permission | $combination;
+ }
+ }
+ return $results;
+ };
+
+ //Generate file permissions
+ $permissions = [
+ \OCP\Constants::PERMISSION_UPDATE,
+ \OCP\Constants::PERMISSION_CREATE,
+ \OCP\Constants::PERMISSION_SHARE,
+ ];
+
+ $allPermissions = $powerset($permissions);
+
+ foreach ($allPermissions as $before) {
+ foreach ($allPermissions as $after) {
+ if ($before === $after) { continue; }
+
+ $data[] = [
+ 'file',
+ $before,
+ $after,
+ ];
+ }
+ }
+
+ //Generate folder permissions
+ $permissions = [
+ \OCP\Constants::PERMISSION_UPDATE,
+ \OCP\Constants::PERMISSION_CREATE,
+ \OCP\Constants::PERMISSION_SHARE,
+ \OCP\Constants::PERMISSION_DELETE,
+ ];
+
+ $allPermissions = $powerset($permissions);
+
+ foreach ($allPermissions as $before) {
+ foreach ($allPermissions as $after) {
+ if ($before === $after) { continue; }
+
+ $data[] = [
+ 'folder',
+ $before,
+ $after,
+ ];
+ }
+ }
+
+ return $data;
+ }
+
+
+
+ /**
+ * moved mountpoints of a group share should keep the same permission as their parent group share.
+ * See #15253
+ *
+ * @dataProvider dataPermissionMovedGroupShare
+ */
+ function testPermissionMovedGroupShare($type, $beforePerm, $afterPerm) {
+
+ if ($type === 'file') {
+ $path = $this->filename;
+ } else if ($type === 'folder') {
+ $path = $this->folder;
+ }
+
+ \OC_Group::createGroup('testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+ // Share item with group
+ $fileinfo = $this->view->getFileInfo($path);
+ $this->assertTrue(
+ \OCP\Share::shareItem($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", $beforePerm)
+ );
+
+ // Login as user 2 and verify the item exists
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($path));
+ $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals($beforePerm, $result['permissions']);
+
+ // Now move the item forcing a new entry in the share table
+ \OC\Files\Filesystem::rename($path, "newPath");
+ $this->assertTrue(\OC\Files\Filesystem::file_exists('newPath'));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($path));
+
+ // Login as user 1 again and change permissions
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ $this->assertTrue(
+ \OCP\Share::setPermissions($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", $afterPerm)
+ );
+
+ // Login as user 3 and verify that the permissions are changed
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals($afterPerm, $result['permissions']);
+ $groupShareId = $result['id'];
+
+ // Login as user 2 and verify that the permissions are changed
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals($afterPerm, $result['permissions']);
+ $this->assertNotEquals($groupShareId, $result['id']);
+
+ // Also verify in the DB
+ $statement = "SELECT `permissions` FROM `*PREFIX*share` WHERE `id`=?";
+ $query = \OCP\DB::prepare($statement);
+ $result = $query->execute([$result['id']]);
+ $shares = $result->fetchAll();
+ $this->assertCount(1, $shares);
+ $this->assertEquals($afterPerm, $shares[0]['permissions']);
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OCP\Share::unshare($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+ }
+
+ /**
+ * If the permissions on a group share are upgraded be sure to still respect
+ * removed shares by a member of that group
+ */
+ function testPermissionUpgradeOnUserDeletedGroupShare() {
+ \OC_Group::createGroup('testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+ $connection = \OC::$server->getDatabaseConnection();
+
+ // Share item with group
+ $fileinfo = $this->view->getFileInfo($this->folder);
+ $this->assertTrue(
+ \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", \OCP\Constants::PERMISSION_READ)
+ );
+
+ // Login as user 2 and verify the item exists
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->folder));
+ $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals(\OCP\Constants::PERMISSION_READ, $result['permissions']);
+
+ // Delete the share
+ $this->assertTrue(\OC\Files\Filesystem::rmdir($this->folder));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->folder));
+
+ // Verify we do not get a share
+ $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']);
+ $this->assertEmpty($result);
+
+ // Verify that the permission is correct in the DB
+ $qb = $connection->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('file_source', $qb->createParameter('fileSource')))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('shareType')))
+ ->setParameter(':fileSource', $fileinfo['fileid'])
+ ->setParameter(':shareType', 2);
+ $res = $qb->execute()->fetchAll();
+
+ $this->assertCount(1, $res);
+ $this->assertEquals(0, $res[0]['permissions']);
+
+ // Login as user 1 again and change permissions
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ $this->assertTrue(
+ \OCP\Share::setPermissions('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", \OCP\Constants::PERMISSION_ALL)
+ );
+
+ // Login as user 2 and verify
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->folder));
+ $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']);
+ $this->assertEmpty($result);
+
+ $connection = \OC::$server->getDatabaseConnection();
+ $qb = $connection->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('file_source', $qb->createParameter('fileSource')))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('shareType')))
+ ->setParameter(':fileSource', $fileinfo['fileid'])
+ ->setParameter(':shareType', 2);
+ $res = $qb->execute()->fetchAll();
+
+ $this->assertCount(1, $res);
+ $this->assertEquals(0, $res[0]['permissions']);
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+ }
+
}
class DummyTestClassSharedMount extends \OCA\Files_Sharing\SharedMount {
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index db27fa6a891..63639461f0a 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -1100,13 +1100,33 @@ class Share extends Constants {
*/
public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
$l = \OC::$server->getL10N('lib');
- if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith,
+ $connection = \OC::$server->getDatabaseConnection();
+
+ $intArrayToLiteralArray = function($intArray, $eb) {
+ return array_map(function($int) use ($eb) {
+ return $eb->literal((int)$int, 'integer');
+ }, $intArray);
+ };
+ $sanitizeItem = function($item) {
+ $item['id'] = (int)$item['id'];
+ $item['premissions'] = (int)$item['permissions'];
+ return $item;
+ };
+
+ if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith,
\OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
// Check if this item is a reshare and verify that the permissions
// granted don't exceed the parent shared item
- if (isset($item['parent'])) {
- $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1);
- $result = $query->execute(array($item['parent']))->fetchRow();
+ if (isset($rootItem['parent'])) {
+ $qb = $connection->getQueryBuilder();
+ $qb->select('permissions')
+ ->from('share')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter(':id', $rootItem['parent']);
+ $dbresult = $qb->execute();
+
+ $result = $dbresult->fetch();
+ $dbresult->closeCursor();
if (~(int)$result['permissions'] & $permissions) {
$message = 'Setting permissions for %s failed,'
.' because the permissions exceed permissions granted to %s';
@@ -1115,8 +1135,13 @@ class Share extends Constants {
throw new \Exception($message_t);
}
}
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
- $query->execute(array($permissions, $item['id']));
+ $qb = $connection->getQueryBuilder();
+ $qb->update('share')
+ ->set('permissions', $qb->createParameter('permissions'))
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter(':id', $rootItem['id'])
+ ->setParameter(':permissions', $permissions);
+ $qb->execute();
if ($itemType === 'file' || $itemType === 'folder') {
\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
'itemType' => $itemType,
@@ -1125,56 +1150,104 @@ class Share extends Constants {
'shareWith' => $shareWith,
'uidOwner' => \OC_User::getUser(),
'permissions' => $permissions,
- 'path' => $item['path'],
- 'share' => $item
+ 'path' => $rootItem['path'],
+ 'share' => $rootItem
));
}
+
+ // Share id's to update with the new permissions
+ $ids = [];
+ $items = [];
+
// Check if permissions were removed
- if ($item['permissions'] & ~$permissions) {
+ if ((int)$rootItem['permissions'] & ~$permissions) {
// If share permission is removed all reshares must be deleted
- if (($item['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
+ if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
// delete all shares, keep parent and group children
- Helper::delete($item['id'], true, null, null, true);
- } else {
- $ids = array();
- $items = [];
- $parents = array($item['id']);
- while (!empty($parents)) {
- $parents = "'".implode("','", $parents)."'";
- $query = \OC_DB::prepare('SELECT `id`, `permissions`, `item_type` FROM `*PREFIX*share`'
- .' WHERE `parent` IN ('.$parents.')');
- $result = $query->execute();
- // Reset parents array, only go through loop again if
- // items are found that need permissions removed
- $parents = array();
- while ($item = $result->fetchRow()) {
- $items[] = $item;
- // Check if permissions need to be removed
- if ($item['permissions'] & ~$permissions) {
- // Add to list of items that need permissions removed
- $ids[] = $item['id'];
- $parents[] = $item['id'];
- }
- }
- }
- // Remove the permissions for all reshares of this item
- if (!empty($ids)) {
- $ids = "'".implode("','", $ids)."'";
- // TODO this should be done with Doctrine platform objects
- if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
- $andOp = 'BITAND(`permissions`, ?)';
- } else {
- $andOp = '`permissions` & ?';
+ Helper::delete($rootItem['id'], true, null, null, true);
+ }
+
+ // Remove permission from all children
+ $parents = [$rootItem['id']];
+ while (!empty($parents)) {
+ $parents = $intArrayToLiteralArray($parents, $qb->expr());
+ $qb = $connection->getQueryBuilder();
+ $qb->select('id', 'permissions', 'item_type')
+ ->from('share')
+ ->where($qb->expr()->in('parent', $parents));
+ $result = $qb->execute();
+ // Reset parents array, only go through loop again if
+ // items are found that need permissions removed
+ $parents = [];
+ while ($item = $result->fetch()) {
+ $item = $sanitizeItem($item);
+
+ $items[] = $item;
+ // Check if permissions need to be removed
+ if ($item['permissions'] & ~$permissions) {
+ // Add to list of items that need permissions removed
+ $ids[] = $item['id'];
+ $parents[] = $item['id'];
}
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
- .' WHERE `id` IN ('.$ids.')');
- $query->execute(array($permissions));
}
+ $result->closeCursor();
+ }
- foreach ($items as $item) {
- \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
+ // Remove the permissions for all reshares of this item
+ if (!empty($ids)) {
+ $ids = "'".implode("','", $ids)."'";
+ // TODO this should be done with Doctrine platform objects
+ if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
+ $andOp = 'BITAND(`permissions`, ?)';
+ } else {
+ $andOp = '`permissions` & ?';
}
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
+ .' WHERE `id` IN ('.$ids.')');
+ $query->execute(array($permissions));
}
+
+ }
+
+ /*
+ * Permissions were added
+ * Update all USERGROUP shares. (So group shares where the user moved their mountpoint).
+ */
+ if ($permissions & ~(int)$rootItem['permissions']) {
+ $qb = $connection->getQueryBuilder();
+ $qb->select('id', 'permissions', 'item_type')
+ ->from('share')
+ ->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type')))
+ ->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted')))
+ ->setParameter(':parent', (int)$rootItem['id'])
+ ->setParameter(':share_type', 2)
+ ->setParameter(':shareDeleted', 0);
+ $result = $qb->execute();
+
+ $ids = [];
+ while ($item = $result->fetch()) {
+ $item = $sanitizeItem($item);
+ $items[] = $item;
+ $ids[] = $item['id'];
+ }
+ $result->closeCursor();
+
+ // Add permssions for all USERGROUP shares of this item
+ if (!empty($ids)) {
+ $ids = $intArrayToLiteralArray($ids, $qb->expr());
+
+ $qb = $connection->getQueryBuilder();
+ $qb->update('share')
+ ->set('permissions', $qb->createParameter('permissions'))
+ ->where($qb->expr()->in('id', $ids))
+ ->setParameter(':permissions', $permissions);
+ $qb->execute();
+ }
+ }
+
+ foreach ($items as $item) {
+ \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
}
return true;