@@ -0,0 +1,32 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace OC\Files\Cache\Wrapper; | |||
class CachePermissionsMask extends CacheWrapper { | |||
/** | |||
* @var int | |||
*/ | |||
protected $mask; | |||
/** | |||
* @param \OC\Files\Cache\Cache $cache | |||
* @param int $mask | |||
*/ | |||
public function __construct($cache, $mask) { | |||
parent::__construct($cache); | |||
$this->mask = $mask; | |||
} | |||
protected function formatCacheEntry($entry) { | |||
if (isset($entry['permissions'])) { | |||
$entry['permissions'] &= $this->mask; | |||
} | |||
return $entry; | |||
} | |||
} |
@@ -9,18 +9,27 @@ | |||
namespace OC\Files\Storage\Wrapper; | |||
use OC\Files\Cache\Wrapper\CachePermissionsMask; | |||
use OCP\Constants; | |||
/** | |||
* Mask the permissions of a storage | |||
* | |||
* This can be used to restrict update, create, delete and/or share permissions of a storage | |||
* | |||
* Note that the read permissions cant be masked | |||
*/ | |||
class PermissionsMask extends Wrapper { | |||
/** | |||
* @var int | |||
* @var int the permissions bits we want to keep | |||
*/ | |||
private $mask; | |||
/** | |||
* @param array $arguments ['storage' => $storage, 'mask' => $mask] | |||
* | |||
* $storage: The storage the permissions mask should be applied on | |||
* $mask: The permission bits that should be kept, a combination of the \OCP\Constant::PERMISSION_ constants | |||
*/ | |||
public function __construct($arguments) { | |||
parent::__construct($arguments); | |||
$this->mask = $arguments['mask']; | |||
@@ -31,15 +40,15 @@ class PermissionsMask extends Wrapper { | |||
} | |||
public function isUpdatable($path) { | |||
return $this->checkMask(\OCP\PERMISSION_UPDATE) and parent::isUpdatable($path); | |||
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::isUpdatable($path); | |||
} | |||
public function isCreatable($path) { | |||
return $this->checkMask(\OCP\PERMISSION_CREATE) and parent::isCreatable($path); | |||
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::isCreatable($path); | |||
} | |||
public function isDeletable($path) { | |||
return $this->checkMask(\OCP\PERMISSION_DELETE) and parent::isDeletable($path); | |||
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::isDeletable($path); | |||
} | |||
public function getPermissions($path) { | |||
@@ -47,32 +56,32 @@ class PermissionsMask extends Wrapper { | |||
} | |||
public function rename($path1, $path2) { | |||
return $this->checkMask(\OCP\PERMISSION_UPDATE) and parent::rename($path1, $path2); | |||
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($path1, $path2); | |||
} | |||
public function copy($path1, $path2) { | |||
return $this->checkMask(\OCP\PERMISSION_CREATE) and parent::copy($path1, $path2); | |||
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($path1, $path2); | |||
} | |||
public function touch($path, $mtime = null) { | |||
$permissions = $this->file_exists($path) ? \OCP\PERMISSION_UPDATE : \OCP\PERMISSION_CREATE; | |||
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; | |||
return $this->checkMask($permissions) and parent::touch($path, $mtime); | |||
} | |||
public function mkdir($path) { | |||
return $this->checkMask(\OCP\PERMISSION_CREATE) and parent::mkdir($path); | |||
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::mkdir($path); | |||
} | |||
public function rmdir($path) { | |||
return $this->checkMask(\OCP\PERMISSION_DELETE) and parent::rmdir($path); | |||
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::rmdir($path); | |||
} | |||
public function unlink($path) { | |||
return $this->checkMask(\OCP\PERMISSION_DELETE) and parent::unlink($path); | |||
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::unlink($path); | |||
} | |||
public function file_put_contents($path, $data) { | |||
$permissions = $this->file_exists($path) ? \OCP\PERMISSION_UPDATE : \OCP\PERMISSION_CREATE; | |||
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; | |||
return $this->checkMask($permissions) and parent::file_put_contents($path, $data); | |||
} | |||
@@ -80,7 +89,7 @@ class PermissionsMask extends Wrapper { | |||
if ($mode === 'r' or $mode === 'rb') { | |||
return parent::fopen($path, $mode); | |||
} else { | |||
$permissions = $this->file_exists($path) ? \OCP\PERMISSION_UPDATE : \OCP\PERMISSION_CREATE; | |||
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; | |||
return $this->checkMask($permissions) ? parent::fopen($path, $mode) : false; | |||
} | |||
} |
@@ -0,0 +1,94 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace Test\Files\Cache\Wrapper; | |||
use OCP\Constants; | |||
use Test\Files\Cache\Cache; | |||
class CachePermissionsMask extends Cache { | |||
/** | |||
* @var \OC\Files\Cache\Cache $sourceCache | |||
*/ | |||
protected $sourceCache; | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->storage->mkdir('foo'); | |||
$this->sourceCache = $this->cache; | |||
$this->cache = $this->getMaskedCached(Constants::PERMISSION_ALL); | |||
} | |||
protected function getMaskedCached($mask) { | |||
return new \OC\Files\Cache\Wrapper\CachePermissionsMask($this->sourceCache, $mask); | |||
} | |||
public function maskProvider() { | |||
return array( | |||
array(Constants::PERMISSION_ALL), | |||
array(Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE), | |||
array(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE), | |||
array(Constants::PERMISSION_READ) | |||
); | |||
} | |||
/** | |||
* @dataProvider maskProvider | |||
* @param int $mask | |||
*/ | |||
public function testGetMasked($mask) { | |||
$cache = $this->getMaskedCached($mask); | |||
$data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'permissions' => Constants::PERMISSION_ALL); | |||
$this->sourceCache->put('foo', $data); | |||
$result = $cache->get('foo'); | |||
$this->assertEquals($mask, $result['permissions']); | |||
$data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE); | |||
$this->sourceCache->put('bar', $data); | |||
$result = $cache->get('bar'); | |||
$this->assertEquals($mask & ~Constants::PERMISSION_DELETE, $result['permissions']); | |||
} | |||
/** | |||
* @dataProvider maskProvider | |||
* @param int $mask | |||
*/ | |||
public function testGetFolderContentMasked($mask) { | |||
$this->storage->mkdir('foo'); | |||
$this->storage->file_put_contents('foo/bar', 'asd'); | |||
$this->storage->file_put_contents('foo/asd', 'bar'); | |||
$this->storage->getScanner()->scan(''); | |||
$cache = $this->getMaskedCached($mask); | |||
$files = $cache->getFolderContents('foo'); | |||
$this->assertCount(2, $files); | |||
foreach ($files as $file) { | |||
$this->assertEquals($mask & ~Constants::PERMISSION_CREATE, $file['permissions']); | |||
} | |||
} | |||
/** | |||
* @dataProvider maskProvider | |||
* @param int $mask | |||
*/ | |||
public function testSearchMasked($mask) { | |||
$this->storage->mkdir('foo'); | |||
$this->storage->file_put_contents('foo/bar', 'asd'); | |||
$this->storage->file_put_contents('foo/foobar', 'bar'); | |||
$this->storage->getScanner()->scan(''); | |||
$cache = $this->getMaskedCached($mask); | |||
$files = $cache->search('%bar'); | |||
$this->assertCount(2, $files); | |||
foreach ($files as $file) { | |||
$this->assertEquals($mask & ~Constants::PERMISSION_CREATE, $file['permissions']); | |||
} | |||
} | |||
} |
@@ -0,0 +1,105 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace Test\Files\Storage\Wrapper; | |||
use OCP\Constants; | |||
class PermissionsMask extends \Test\Files\Storage\Storage { | |||
/** | |||
* @var \OC\Files\Storage\Temporary | |||
*/ | |||
private $sourceStorage; | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->sourceStorage = new \OC\Files\Storage\Temporary(array()); | |||
$this->instance = $this->getMaskedStorage(Constants::PERMISSION_ALL); | |||
} | |||
public function tearDown() { | |||
$this->sourceStorage->cleanUp(); | |||
parent::tearDown(); | |||
} | |||
protected function getMaskedStorage($mask) { | |||
return new \OC\Files\Storage\Wrapper\PermissionsMask(array( | |||
'storage' => $this->sourceStorage, | |||
'mask' => $mask | |||
)); | |||
} | |||
public function testMkdirNoCreate() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); | |||
$this->assertFalse($storage->mkdir('foo')); | |||
$this->assertFalse($storage->file_exists('foo')); | |||
} | |||
public function testRmdirNoDelete() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE); | |||
$this->assertTrue($storage->mkdir('foo')); | |||
$this->assertTrue($storage->file_exists('foo')); | |||
$this->assertFalse($storage->rmdir('foo')); | |||
$this->assertTrue($storage->file_exists('foo')); | |||
} | |||
public function testTouchNewFileNoCreate() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); | |||
$this->assertFalse($storage->touch('foo')); | |||
$this->assertFalse($storage->file_exists('foo')); | |||
} | |||
public function testTouchNewFileNoUpdate() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); | |||
$this->assertTrue($storage->touch('foo')); | |||
$this->assertTrue($storage->file_exists('foo')); | |||
} | |||
public function testTouchExistingFileNoUpdate() { | |||
$this->sourceStorage->touch('foo'); | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); | |||
$this->assertFalse($storage->touch('foo')); | |||
} | |||
public function testUnlinkNoDelete() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE); | |||
$this->assertTrue($storage->touch('foo')); | |||
$this->assertTrue($storage->file_exists('foo')); | |||
$this->assertFalse($storage->unlink('foo')); | |||
$this->assertTrue($storage->file_exists('foo')); | |||
} | |||
public function testPutContentsNewFileNoUpdate() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); | |||
$this->assertTrue($storage->file_put_contents('foo', 'bar')); | |||
$this->assertEquals('bar', $storage->file_get_contents('foo')); | |||
} | |||
public function testPutContentsNewFileNoCreate() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); | |||
$this->assertFalse($storage->file_put_contents('foo', 'bar')); | |||
} | |||
public function testPutContentsExistingFileNoUpdate() { | |||
$this->sourceStorage->touch('foo'); | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); | |||
$this->assertFalse($storage->file_put_contents('foo', 'bar')); | |||
} | |||
public function testFopenExistingFileNoUpdate() { | |||
$this->sourceStorage->touch('foo'); | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); | |||
$this->assertFalse($storage->fopen('foo', 'w')); | |||
} | |||
public function testFopenNewFileNoCreate() { | |||
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); | |||
$this->assertFalse($storage->fopen('foo', 'w')); | |||
} | |||
} |