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

getNode optimizations #439

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 3 additions & 1 deletion lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorage;
use OCP\Util;
use OCP\WorkflowEngine\Events\RegisterOperationsEvent;
Expand All @@ -53,13 +54,14 @@ public function addStorageWrapper() {
* @param IStorage $storage
* @return StorageWrapper|IStorage
*/
public function addStorageWrapperCallback($mountPoint, IStorage $storage) {
public function addStorageWrapperCallback($mountPoint, IStorage $storage, IMountPoint $mount) {
if (!OC::$CLI && $mountPoint !== '/') {
/** @var Operation $operation */
$operation = $this->getContainer()->get(Operation::class);
return new StorageWrapper([
'storage' => $storage,
'mountPoint' => $mountPoint,
'mount' => $mount,
'operation' => $operation,
]);
}
Expand Down
21 changes: 13 additions & 8 deletions lib/CacheWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,24 @@
namespace OCA\FilesAccessControl;

use OC\Files\Cache\Wrapper\CacheWrapper as Wrapper;
use OC\Files\Storage\Wrapper\Jail;
use OCP\Constants;
use OCP\Files\Cache\ICache;
use OCP\Files\ForbiddenException;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorage;

class CacheWrapper extends Wrapper {
protected Operation $operation;
protected IStorage $storage;
protected IMountPoint $mountPoint;
protected int $mask;

/**
* @param ICache $cache
* @param IStorage $storage
* @param Operation $operation
*/
public function __construct(ICache $cache, IStorage $storage, Operation $operation) {
public function __construct(ICache $cache, Operation $operation, IMountPoint $mountPoint) {
parent::__construct($cache);
$this->storage = $storage;
$this->storage = $mountPoint->getStorage();
$this->operation = $operation;
$this->mountPoint = $mountPoint;

$this->mask = Constants::PERMISSION_ALL;
$this->mask &= ~Constants::PERMISSION_READ;
Expand All @@ -57,7 +56,13 @@ public function __construct(ICache $cache, IStorage $storage, Operation $operati
protected function formatCacheEntry($entry) {
if (isset($entry['path']) && isset($entry['permissions'])) {
try {
$this->operation->checkFileAccess($this->storage, $entry['path'], $entry['mimetype'] === 'httpd/unix-directory', $entry);
$storage = $this->storage;
$path = $entry['path'];
if ($storage->instanceOfStorage(Jail::class)) {
/** @var Jail $storage */
$path = $storage->getJailedPath($path);
}
$this->operation->checkFileAccess($path, $this->mountPoint, $entry['mimetype'] === 'httpd/unix-directory', $entry);
} catch (ForbiddenException $e) {
$entry['permissions'] &= $this->mask;
}
Expand Down
60 changes: 19 additions & 41 deletions lib/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,21 @@ public function __construct(
* @param array|ICacheEntry|null $cacheEntry
* @throws ForbiddenException
*/
public function checkFileAccess(IStorage $storage, string $path, bool $isDir = false, $cacheEntry = null): void {
if (!$this->isBlockablePath($storage, $path) || $this->isCreatingSkeletonFiles() || $this->nestingLevel !== 0) {
public function checkFileAccess(string $path, IMountPoint $mountPoint, bool $isDir, $cacheEntry = null): void {
if (!$this->isBlockablePath($mountPoint, $path) || $this->isCreatingSkeletonFiles() || $this->nestingLevel !== 0) {
// Allow creating skeletons and theming
// https://github.com/nextcloud/files_accesscontrol/issues/5
// https://github.com/nextcloud/files_accesscontrol/issues/12
return;
}
$storage = $mountPoint->getStorage();

$this->nestingLevel++;

$filePath = $this->translatePath($storage, $path);
$ruleMatcher = $this->manager->getRuleMatcher();
$ruleMatcher->setFileInfo($storage, $filePath, $isDir);
$node = $this->getNode($storage, $path, $cacheEntry);
$node = $this->getNode($path, $mountPoint, $cacheEntry);
if ($node !== null) {
$ruleMatcher->setEntitySubject($this->fileEntity, $node);
}
Expand All @@ -107,24 +108,8 @@ public function checkFileAccess(IStorage $storage, string $path, bool $isDir = f
}
}

protected function isBlockablePath(IStorage $storage, string $path): bool {
if (property_exists($storage, 'mountPoint')) {
$hasMountPoint = $storage instanceof StorageWrapper;
if (!$hasMountPoint) {
$ref = new ReflectionClass($storage);
$prop = $ref->getProperty('mountPoint');
$hasMountPoint = $prop->isPublic();
}

if ($hasMountPoint) {
/** @var StorageWrapper $storage */
$fullPath = $storage->mountPoint . ltrim($path, '/');
} else {
$fullPath = $path;
}
} else {
$fullPath = $path;
}
protected function isBlockablePath(IMountPoint $mountPoint, string $path): bool {
$fullPath = $mountPoint->getMountPoint() . ltrim($path, '/');

if (substr_count($fullPath, '/') < 3) {
return false;
Expand Down Expand Up @@ -289,30 +274,23 @@ public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatch
/**
* @param array|ICacheEntry|null $cacheEntry
*/
private function getNode(IStorage $storage, string $path, $cacheEntry = null): ?Node {
/** @var IMountPoint|false $mountPoint */
$mountPoint = current($this->mountManager->findByStorageId($storage->getId()));
if (!$mountPoint) {
private function getNode(string $path, IMountPoint $mountPoint, $cacheEntry = null): ?Node {
$fullPath = $mountPoint->getMountPoint() . $path;
if (!$cacheEntry) {
$cacheEntry = $mountPoint->getStorage()->getCache()->get($path);
}
if (!$cacheEntry) {
return null;
}

$fullPath = $mountPoint->getMountPoint() . $path;
if ($cacheEntry) {
// todo: LazyNode?
$info = new FileInfo($fullPath, $mountPoint->getStorage(), $path, $cacheEntry, $mountPoint);
$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
$view = new View('');
if ($isDir) {
return new Folder($this->rootFolder, $view, $path, $info);
} else {
return new \OC\Files\Node\File($this->rootFolder, $view, $path, $info);
}
// todo: LazyNode?
$info = new FileInfo($fullPath, $mountPoint->getStorage(), $path, $cacheEntry, $mountPoint);
$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
$view = new View('');
if ($isDir) {
return new Folder($this->rootFolder, $view, $path, $info);
} else {
try {
return $this->rootFolder->get($fullPath);
} catch (NotFoundException $e) {
return null;
}
return new \OC\Files\Node\File($this->rootFolder, $view, $path, $info);
}
}
}
7 changes: 5 additions & 2 deletions lib/StorageWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
use OC\Files\Storage\Wrapper\Wrapper;
use OCP\Constants;
use OCP\Files\ForbiddenException;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorage;
use OCP\Files\Storage\IWriteStreamStorage;

class StorageWrapper extends Wrapper implements IWriteStreamStorage {
/** @var Operation */
protected $operation;
protected IMountPoint $mount;

/** @var string */
public $mountPoint;
Expand All @@ -45,6 +47,7 @@ public function __construct($parameters) {
parent::__construct($parameters);
$this->operation = $parameters['operation'];
$this->mountPoint = $parameters['mountPoint'];
$this->mount = $parameters['mount'];

$this->mask = Constants::PERMISSION_ALL;
$this->mask &= ~Constants::PERMISSION_READ;
Expand All @@ -57,7 +60,7 @@ public function __construct($parameters) {
* @throws ForbiddenException
*/
protected function checkFileAccess(string $path, bool $isDir = false): void {
$this->operation->checkFileAccess($this, $path, $isDir);
$this->operation->checkFileAccess($path, $this->mount, $isDir);
}

/*
Expand Down Expand Up @@ -261,7 +264,7 @@ public function getCache($path = '', $storage = null) {
$storage = $this;
}
$cache = $this->storage->getCache($path, $storage);
return new CacheWrapper($cache, $storage, $this->operation);
return new CacheWrapper($cache, $this->operation, $this->mount);
}

/**
Expand Down
11 changes: 10 additions & 1 deletion tests/Unit/StorageWrapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use OCA\FilesAccessControl\Operation;
use OCA\FilesAccessControl\StorageWrapper;
use OCP\Files\ForbiddenException;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorage;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
Expand All @@ -38,12 +39,19 @@ class StorageWrapperTest extends TestCase {
/** @var Operation|MockObject */
protected $operation;

/** @var IMountPoint|MockObject */
protected $mountPoint;

protected function setUp(): void {
parent::setUp();

$this->storage = $this->createMock(IStorage::class);

$this->operation = $this->createMock(Operation::class);

$this->mountPoint = $this->createMock(IMountPoint::class);
$this->mountPoint->method('getMountPoint')->willReturn('mountPoint');
$this->mountPoint->method('getStorage')->willReturn($this->storage);
}

protected function getInstance(array $methods = []) {
Expand All @@ -52,6 +60,7 @@ protected function getInstance(array $methods = []) {
[
'storage' => $this->storage,
'mountPoint' => 'mountPoint',
'mount' => $this->mountPoint,
'operation' => $this->operation,
]
])
Expand All @@ -75,7 +84,7 @@ public function testCheckFileAccess(string $path): void {

$this->operation->expects($this->once())
->method('checkFileAccess')
->with($storage, $path);
->with($path, $this->mountPoint, false);

self::invokePrivate($storage, 'checkFileAccess', [$path]);
}
Expand Down