Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port isTargetAllowed to share 2.0 #26615

Merged
merged 1 commit into from
Nov 29, 2016
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
11 changes: 11 additions & 0 deletions apps/files_sharing/lib/External/Mount.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,15 @@ public function moveMount($target) {
public function removeMount() {
return $this->manager->removeShare($this->mountPoint);
}

/**
* Returns true
*
* @param string $target unused
* @return bool true
*/
public function isTargetAllowed($target) {
// note: home storage check already done in View
return true;
}
}
48 changes: 48 additions & 0 deletions apps/files_sharing/lib/SharedMount.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use OC\Files\Mount\MountPoint;
use OC\Files\Mount\MoveableMount;
use OC\Files\View;
use OCP\Share\IShare;

/**
* Shared mount points can be moved by the user
Expand Down Expand Up @@ -178,13 +179,60 @@ protected function stripUserFilesPath($path) {
return '/' . $relPath;
}

/**
* Check whether it is allowed to move a mount point to a given target.
* It is not allowed to move a mount point into a different mount point or
* into an already shared folder
*
* @param string $target absolute target path
* @return bool true if allowed, false otherwise
*/
public function isTargetAllowed($target) {
list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target);
// note: cannot use the view because the target is already locked
$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
if ($fileId === -1) {
// target might not exist, need to check parent instead
$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
}

$targetNodes = \OC::$server->getRootFolder()->getById($fileId);
if (empty($targetNodes)) {
return false;
}

$shareManager = \OC::$server->getShareManager();
$targetNode = $targetNodes[0];
// FIXME: make it stop earlier in '/$userId/files'
while (!is_null($targetNode) && $targetNode->getPath() !== '/') {
$shares = $shareManager->getSharesByPath($targetNode);

foreach ($shares as $share) {
if ($this->user === $share->getShareOwner()) {
\OCP\Util::writeLog('files',
'It is not allowed to move one mount point into a shared folder',
\OCP\Util::DEBUG);
return false;
}
}

$targetNode = $targetNode->getParent();
}

return true;
}


/**
* Move the mount point to $target
*
* @param string $target the target mount point
* @return bool
*/
public function moveMount($target) {
if (!$this->isTargetAllowed($target)) {
return false;
}

$relTargetPath = $this->stripUserFilesPath($target);
$share = $this->storage->getShare();
Expand Down
55 changes: 55 additions & 0 deletions apps/files_sharing/tests/SharedMountTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

namespace OCA\Files_Sharing\Tests;

use OCP\Files\NotPermittedException;

/**
* Class SharedMountTest
*
Expand Down Expand Up @@ -388,6 +390,59 @@ function testPermissionUpgradeOnUserDeletedGroupShare() {
\OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
}

public function testIsTargetAllowed() {
$user1 = self::TEST_FILES_SHARING_API_USER1;
$user2 = self::TEST_FILES_SHARING_API_USER2;
$user3 = self::TEST_FILES_SHARING_API_USER3;

// user1 shares with user2
$userFolder = \OC::$server->getUserFolder($user1);
$sharedFolder = $userFolder->newFolder('user1-share');

$share = $this->share(
\OCP\Share::SHARE_TYPE_USER,
$sharedFolder,
$user1,
$user2,
\OCP\Constants::PERMISSION_ALL);

$this->loginAsUser($user2);

// user2 shares with user3
$userFolder2 = \OC::$server->getUserFolder($user2);

$sharedFolder2 = $userFolder2->newFolder('shareddir');
$userFolder2->newFolder('shareddir/sub');
$userFolder2->newFolder('shareddir/sub2');

$share2 = $this->share(
\OCP\Share::SHARE_TYPE_USER,
$sharedFolder2,
$user2,
$user3,
\OCP\Constants::PERMISSION_ALL);

$receivedFolder = $userFolder2->get('user1-share');

// cannot move into any of these dirs
foreach ([
'/' . $user2 . '/files/shareddir',
'/' . $user2 . '/files/shareddir/sub',
'/' . $user2 . '/files/shareddir/sub2',
] as $targetDir) {
$caught = null;
try {
$receivedFolder->move($targetDir);
} catch (NotPermittedException $e) {
$caught = $e;
}

$this->assertInstanceOf('\OCP\Files\NotPermittedException', $e);
}

$this->shareManager->deleteShare($share);
$this->shareManager->deleteShare($share2);
}
}

class DummyTestClassSharedMount extends \OCA\Files_Sharing\SharedMount {
Expand Down
8 changes: 6 additions & 2 deletions apps/files_sharing/tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,12 @@ protected function getShareFromId($shareID) {
* @return \OCP\Share\IShare
*/
protected function share($type, $path, $initiator, $recipient, $permissions) {
$userFolder = $this->rootFolder->getUserFolder($initiator);
$node = $userFolder->get($path);
if (is_string($path)) {
$userFolder = $this->rootFolder->getUserFolder($initiator);
$node = $userFolder->get($path);
} else {
$node = $path;
}

$share = $this->shareManager->newShare();
$share->setShareType($type)
Expand Down
11 changes: 11 additions & 0 deletions lib/private/Files/External/PersonalMount.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,15 @@ public function removeMount() {
$this->storagesService->removeStorage($this->numericStorageId);
return true;
}

/**
* Returns true
*
* @param string $target unused
* @return bool true
*/
public function isTargetAllowed($target) {
// note: home storage check already done in View
return true;
}
}
11 changes: 11 additions & 0 deletions lib/private/Files/Mount/MoveableMount.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,15 @@ public function moveMount($target);
* @return bool
*/
public function removeMount();

/**
* Returns whether this mount point is allowed to be moved into the given absolute target
*
* @param string $target absolute target path
*
* @return bool true if allowed, false otherwise
*
* @since 9.2
*/
public function isTargetAllowed($target);
}
32 changes: 5 additions & 27 deletions lib/private/Files/View.php
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ public function rename($path1, $path2) {
$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);

if ($internalPath1 === '' and $mount1 instanceof MoveableMount) {
if ($this->isTargetAllowed($absolutePath2)) {
if ($this->canMove($mount1, $absolutePath2)) {
/**
* @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
*/
Expand Down Expand Up @@ -1726,10 +1726,11 @@ private function assertPathLength($path) {
* It is not allowed to move a mount point into a different mount point or
* into an already shared folder
*
* @param string $target path
* @param MoveableMount $mount1 moveable mount
* @param string $target absolute target path
* @return boolean
*/
private function isTargetAllowed($target) {
private function canMove(MoveableMount $mount1, $target) {

list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target);
if (!$targetStorage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
Expand All @@ -1739,30 +1740,7 @@ private function isTargetAllowed($target) {
return false;
}

// note: cannot use the view because the target is already locked
$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
if ($fileId === -1) {
// target might not exist, need to check parent instead
$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
}

// check if any of the parents were shared by the current owner (include collections)
$shares = \OCP\Share::getItemShared(
'folder',
$fileId,
\OCP\Share::FORMAT_NONE,
null,
true
);

if (count($shares) > 0) {
\OCP\Util::writeLog('files',
'It is not allowed to move one mount point into a shared folder',
\OCP\Util::DEBUG);
return false;
}

return true;
return $mount1->isTargetAllowed($target);
}

/**
Expand Down
15 changes: 15 additions & 0 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,21 @@ public function getShareById($id, $recipient = null) {
* @return Share[]
*/
public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP];
$providers = [];
$results = [];

foreach ($types as $type) {
$provider = $this->factory->getProviderForType($type);
// store this way to deduplicate entries by id
$providers[$provider->identifier()] = $provider;
}

foreach ($providers as $provider) {
$results = array_merge($results, $provider->getSharesByPath($path));
}

return $results;
}

/**
Expand Down
40 changes: 14 additions & 26 deletions tests/lib/Files/ViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1519,17 +1519,22 @@ public function testHookPaths($root, $path, $shouldEmit) {
* Create test movable mount points
*
* @param array $mountPoints array of mount point locations
* @param bool $isTargetAllowed value to return for the isTargetAllowed call
* @return array array of MountPoint objects
*/
private function createTestMovableMountPoints($mountPoints) {
private function createTestMovableMountPoints($mountPoints, $isTargetAllowed = true) {
$mounts = [];
foreach ($mountPoints as $mountPoint) {
$storage = new Temporary();

$mounts[] = $this->getMockBuilder('\Test\TestMoveableMountPoint')
->setMethods(['moveMount'])
$testMount = $this->getMockBuilder('\Test\TestMoveableMountPoint')
->setMethods(['moveMount', 'isTargetAllowed'])
->setConstructorArgs([$storage, $mountPoint])
->getMock();
$testMount->expects($this->any())
->method('isTargetAllowed')
->will($this->returnValue($isTargetAllowed));
$mounts[] = $testMount;
}

$mountProvider = $this->createMock('\OCP\Files\Config\IMountProvider');
Expand Down Expand Up @@ -1592,43 +1597,26 @@ public function testMoveMountPointIntoAnother() {
}

/**
* Test that moving a mount point into a shared folder is forbidden
* Test that moving a mount point that says it's not allowed will fail
*/
public function testMoveMountPointIntoSharedFolder() {
public function testMoveMountPointNotAllowed() {
$this->loginAsUser($this->user);

$userFolder = \OC::$server->getUserFolder($this->user);

list($mount1) = $this->createTestMovableMountPoints([
$this->user . '/files/mount1',
]);
], false);

$mount1->expects($this->never())
->method('moveMount');

$view = new View('/' . $this->user . '/files/');
$view->mkdir('shareddir');
$view->mkdir('shareddir/sub');
$view->mkdir('shareddir/sub2');

$userObject = \OC::$server->getUserManager()->createUser('test2', 'IHateNonMockableStaticClasses');

$sharedFolder = \OC::$server->getUserFolder($this->user)->get('shareddir');
$shareManager = \OC::$server->getShareManager();
$share = $shareManager->newShare();
$share->setSharedBy($this->user);
$share->setShareType(\OCP\Share::SHARE_TYPE_USER);
$share->setNode($sharedFolder);
$share->setSharedWith('test2');
$share->setPermissions(\OCP\Constants::PERMISSION_READ);
$share = $shareManager->createShare($share);
$view->mkdir('somedir');

$this->assertFalse($view->rename('mount1', 'shareddir'), 'Cannot overwrite shared folder');
$this->assertFalse($view->rename('mount1', 'shareddir/sub'), 'Cannot move mount point into shared folder');
$this->assertFalse($view->rename('mount1', 'shareddir/sub/sub2'), 'Cannot move mount point into shared subfolder');
$fileId = $view->getFileInfo('somedir')->getId();

$shareManager->deleteShare($share);
$userObject->delete();
$this->assertFalse($view->rename('mount1', 'shareddir'), 'Cannot overwrite shared folder');
}

public function basicOperationProviderForLocks() {
Expand Down
Loading