mirror of
https://github.com/nextcloud/server.git
synced 2026-06-13 18:50:47 -04:00
Merge pull request #59511 from nextcloud/public-share-only-mask-home
Only mask the permissions for the users home directory for public shares
This commit is contained in:
commit
14472cb8cc
8 changed files with 245 additions and 6 deletions
|
|
@ -6,7 +6,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
use OC\Files\Filesystem;
|
||||
use OC\Files\Storage\Wrapper\PermissionsMask;
|
||||
use OC\Files\Storage\Wrapper\DirPermissionsMask;
|
||||
use OC\Files\View;
|
||||
use OCA\DAV\Connector\LegacyPublicAuth;
|
||||
use OCA\DAV\Connector\Sabre\ServerFactory;
|
||||
|
|
@ -98,7 +98,11 @@ $server = $serverFactory->createServer(
|
|||
// FIXME: should not add storage wrappers outside of preSetup, need to find a better way
|
||||
$previousLog = Filesystem::logWarningWhenAddingStorageWrapper(false);
|
||||
Filesystem::addStorageWrapper('sharePermissions', function ($mountPoint, $storage) use ($share) {
|
||||
return new PermissionsMask(['storage' => $storage, 'mask' => $share->getPermissions() | Constants::PERMISSION_SHARE]);
|
||||
return new DirPermissionsMask([
|
||||
'storage' => $storage,
|
||||
'mask' => $share->getPermissions() | Constants::PERMISSION_SHARE,
|
||||
'path' => 'files'
|
||||
]);
|
||||
});
|
||||
Filesystem::addStorageWrapper('shareOwner', function ($mountPoint, $storage) use ($share) {
|
||||
return new PublicOwnerWrapper(['storage' => $storage, 'owner' => $share->getShareOwner()]);
|
||||
|
|
|
|||
|
|
@ -11,13 +11,14 @@ namespace OCA\Files_External\Lib;
|
|||
|
||||
use OC\Files\Storage\Wrapper\PermissionsMask;
|
||||
use OCP\Constants;
|
||||
use OCP\Files\Storage\IStorage;
|
||||
|
||||
/**
|
||||
* Wrap Storage in PermissionsMask for session ephemeral use
|
||||
*/
|
||||
class SessionStorageWrapper extends PermissionsMask {
|
||||
/**
|
||||
* @param array $parameters ['storage' => $storage]
|
||||
* @param array{storage: IStorage, ...} $parameters
|
||||
*/
|
||||
public function __construct(array $parameters) {
|
||||
// disable sharing permission
|
||||
|
|
|
|||
|
|
@ -1733,6 +1733,7 @@ return array(
|
|||
'OC\\Files\\Cache\\StorageGlobal' => $baseDir . '/lib/private/Files/Cache/StorageGlobal.php',
|
||||
'OC\\Files\\Cache\\Updater' => $baseDir . '/lib/private/Files/Cache/Updater.php',
|
||||
'OC\\Files\\Cache\\Watcher' => $baseDir . '/lib/private/Files/Cache/Watcher.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CacheDirPermissionsMask' => $baseDir . '/lib/private/Files/Cache/Wrapper/CacheDirPermissionsMask.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CacheJail' => $baseDir . '/lib/private/Files/Cache/Wrapper/CacheJail.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CachePermissionsMask' => $baseDir . '/lib/private/Files/Cache/Wrapper/CachePermissionsMask.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CacheWrapper' => $baseDir . '/lib/private/Files/Cache/Wrapper/CacheWrapper.php',
|
||||
|
|
@ -1818,6 +1819,7 @@ return array(
|
|||
'OC\\Files\\Storage\\StorageFactory' => $baseDir . '/lib/private/Files/Storage/StorageFactory.php',
|
||||
'OC\\Files\\Storage\\Temporary' => $baseDir . '/lib/private/Files/Storage/Temporary.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\Availability' => $baseDir . '/lib/private/Files/Storage/Wrapper/Availability.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\DirPermissionsMask' => $baseDir . '/lib/private/Files/Storage/Wrapper/DirPermissionsMask.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\Encoding' => $baseDir . '/lib/private/Files/Storage/Wrapper/Encoding.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\EncodingDirectoryWrapper' => $baseDir . '/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\Encryption' => $baseDir . '/lib/private/Files/Storage/Wrapper/Encryption.php',
|
||||
|
|
|
|||
|
|
@ -1774,6 +1774,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OC\\Files\\Cache\\StorageGlobal' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/StorageGlobal.php',
|
||||
'OC\\Files\\Cache\\Updater' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Updater.php',
|
||||
'OC\\Files\\Cache\\Watcher' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Watcher.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CacheDirPermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Wrapper/CacheDirPermissionsMask.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CacheJail' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Wrapper/CacheJail.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CachePermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Wrapper/CachePermissionsMask.php',
|
||||
'OC\\Files\\Cache\\Wrapper\\CacheWrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Wrapper/CacheWrapper.php',
|
||||
|
|
@ -1859,6 +1860,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OC\\Files\\Storage\\StorageFactory' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/StorageFactory.php',
|
||||
'OC\\Files\\Storage\\Temporary' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Temporary.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\Availability' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Availability.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\DirPermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/DirPermissionsMask.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\Encoding' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Encoding.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\EncodingDirectoryWrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php',
|
||||
'OC\\Files\\Storage\\Wrapper\\Encryption' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Encryption.php',
|
||||
|
|
|
|||
36
lib/private/Files/Cache/Wrapper/CacheDirPermissionsMask.php
Normal file
36
lib/private/Files/Cache/Wrapper/CacheDirPermissionsMask.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OC\Files\Cache\Wrapper;
|
||||
|
||||
use Closure;
|
||||
use OCP\Files\Cache\ICache;
|
||||
use OCP\Files\Cache\ICacheEntry;
|
||||
|
||||
class CacheDirPermissionsMask extends CachePermissionsMask {
|
||||
/**
|
||||
* @param Closure(string $path): bool $checkPath
|
||||
*/
|
||||
public function __construct(
|
||||
ICache $cache,
|
||||
int $mask,
|
||||
private readonly Closure $checkPath,
|
||||
) {
|
||||
parent::__construct($cache, $mask);
|
||||
}
|
||||
|
||||
protected function formatCacheEntry($entry): ICacheEntry|false {
|
||||
$checkPath = $this->checkPath;
|
||||
if ($checkPath($entry['path'])) {
|
||||
return parent::formatCacheEntry($entry);
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
}
|
||||
193
lib/private/Files/Storage/Wrapper/DirPermissionsMask.php
Normal file
193
lib/private/Files/Storage/Wrapper/DirPermissionsMask.php
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only AND (AGPL-3.0-or-later OR AGPL-3.0-only)
|
||||
*/
|
||||
|
||||
namespace OC\Files\Storage\Wrapper;
|
||||
|
||||
use OC\Files\Cache\Wrapper\CacheDirPermissionsMask;
|
||||
use OC\Files\Storage\Storage;
|
||||
use OCP\Files\Cache\ICache;
|
||||
|
||||
/**
|
||||
* While PermissionMask can mask a whole storage this can
|
||||
* mask a certain directory inside a storage
|
||||
*/
|
||||
class DirPermissionsMask extends PermissionsMask {
|
||||
|
||||
/**
|
||||
* @var string the dir that should be masked
|
||||
*/
|
||||
private readonly string $path;
|
||||
|
||||
/**
|
||||
* @var int remember length
|
||||
*/
|
||||
private readonly int $pathLength;
|
||||
|
||||
/**
|
||||
* @param array{storage: Storage, mask: int, path: string, ...} $parameters
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*
|
||||
* $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
|
||||
* $path: The path relative to the storage root that should be masked
|
||||
*/
|
||||
public function __construct($parameters) {
|
||||
parent::__construct($parameters);
|
||||
$this->path = rtrim((string)$parameters['path'], '/');
|
||||
$this->pathLength = strlen((string)$parameters['path']);
|
||||
}
|
||||
|
||||
protected function checkPath(string $path): bool {
|
||||
return $path === $this->path || substr($path, 0, $this->pathLength + 1) === $this->path . '/';
|
||||
}
|
||||
|
||||
public function isUpdatable($path): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::isUpdatable($path);
|
||||
}
|
||||
|
||||
return $this->storage->isUpdatable($path);
|
||||
}
|
||||
|
||||
public function isCreatable($path): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::isCreatable($path);
|
||||
}
|
||||
|
||||
return $this->storage->isCreatable($path);
|
||||
}
|
||||
|
||||
public function isDeletable($path): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::isDeletable($path);
|
||||
}
|
||||
|
||||
return $this->storage->isDeletable($path);
|
||||
}
|
||||
|
||||
public function isSharable($path): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::isSharable($path);
|
||||
}
|
||||
|
||||
return $this->storage->isSharable($path);
|
||||
}
|
||||
|
||||
public function getPermissions($path): int {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::getPermissions($path);
|
||||
}
|
||||
|
||||
return $this->storage->getPermissions($path);
|
||||
}
|
||||
|
||||
public function rename($source, $target): bool {
|
||||
if (!$this->isUpdatable($source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->file_exists($target)) {
|
||||
if ($this->isUpdatable($target)) {
|
||||
return $this->storage->rename($source, $target);
|
||||
}
|
||||
} else {
|
||||
$parent = dirname($target);
|
||||
if ($parent === '.') {
|
||||
$parent = '';
|
||||
}
|
||||
|
||||
if ($this->isCreatable($parent)) {
|
||||
return $this->storage->rename($source, $target);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function copy($source, $target): bool {
|
||||
if (!$this->isReadable($source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->file_exists($target)) {
|
||||
if ($this->isUpdatable($target)) {
|
||||
return $this->storage->copy($source, $target);
|
||||
}
|
||||
} else {
|
||||
$parent = dirname($target);
|
||||
if ($parent === '.') {
|
||||
$parent = '';
|
||||
}
|
||||
|
||||
if ($this->isCreatable($parent)) {
|
||||
return $this->storage->copy($source, $target);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function touch($path, $mtime = null): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::touch($path);
|
||||
}
|
||||
|
||||
return $this->storage->touch($path);
|
||||
}
|
||||
|
||||
public function mkdir($path): bool {
|
||||
// Always allow creating the path of the dir mask.
|
||||
if ($path !== $this->path && $this->checkPath($path)) {
|
||||
return parent::mkdir($path);
|
||||
}
|
||||
|
||||
return $this->storage->mkdir($path);
|
||||
}
|
||||
|
||||
public function rmdir($path): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::rmdir($path);
|
||||
}
|
||||
|
||||
return $this->storage->rmdir($path);
|
||||
}
|
||||
|
||||
public function unlink($path): bool {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::unlink($path);
|
||||
}
|
||||
|
||||
return $this->storage->unlink($path);
|
||||
}
|
||||
|
||||
public function file_put_contents($path, $data): int|float|false {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::file_put_contents($path, $data);
|
||||
}
|
||||
|
||||
return $this->storage->file_put_contents($path, $data);
|
||||
}
|
||||
|
||||
public function fopen($path, $mode) {
|
||||
if ($this->checkPath($path)) {
|
||||
return parent::fopen($path, $mode);
|
||||
}
|
||||
|
||||
return $this->storage->fopen($path, $mode);
|
||||
}
|
||||
|
||||
public function getCache($path = '', $storage = null): ICache {
|
||||
if (!$storage) {
|
||||
$storage = $this;
|
||||
}
|
||||
|
||||
$sourceCache = $this->storage->getCache($path, $storage);
|
||||
return new CacheDirPermissionsMask($sourceCache, $this->mask, $this->checkPath(...));
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
namespace OC\Files\Storage\Wrapper;
|
||||
|
||||
use OC\Files\Cache\Wrapper\CachePermissionsMask;
|
||||
use OC\Files\Storage\Storage;
|
||||
use OCP\Constants;
|
||||
use OCP\Files\Cache\ICache;
|
||||
use OCP\Files\Cache\IScanner;
|
||||
|
|
@ -24,10 +25,10 @@ class PermissionsMask extends Wrapper {
|
|||
/**
|
||||
* @var int the permissions bits we want to keep
|
||||
*/
|
||||
private $mask;
|
||||
protected readonly int $mask;
|
||||
|
||||
/**
|
||||
* @param array $parameters ['storage' => $storage, 'mask' => $mask]
|
||||
* @param array{storage: Storage, mask: int, ...} $parameters
|
||||
*
|
||||
* $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
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class Wrapper implements Storage, ILockingStorage, IWriteStreamStorage {
|
|||
public ?IUpdater $updater = null;
|
||||
|
||||
/**
|
||||
* @param array{storage: Storage} $parameters
|
||||
* @param array{storage: Storage, ...} $parameters
|
||||
*/
|
||||
public function __construct(array $parameters) {
|
||||
$this->storage = $parameters['storage'];
|
||||
|
|
|
|||
Loading…
Reference in a new issue