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

Add hidden user folder #29886

Closed
wants to merge 7 commits into from
Closed
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
17 changes: 17 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,23 @@ steps:
- cd build/integration
- ./run.sh features/webdav-related.feature

---
kind: pipeline
name: integration-webdav-hidden-folder

steps:
- name: submodules
image: ghcr.io/nextcloud/continuous-integration-alpine-git:latest
commands:
- git submodule update --init
- name: integration-webdav-related
image: ghcr.io/nextcloud/continuous-integration-integration-php7.3:latest
commands:
- bash tests/drone-run-integration-tests.sh || exit 0
- ./occ maintenance:install --admin-pass=admin --data-dir=/dev/shm/nc_int
- cd build/integration
- ./run.sh features/hidden-folder.feature

trigger:
branch:
- master
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@
'OCA\\DAV\\Files\\BrowserErrorPagePlugin' => $baseDir . '/../lib/Files/BrowserErrorPagePlugin.php',
'OCA\\DAV\\Files\\FileSearchBackend' => $baseDir . '/../lib/Files/FileSearchBackend.php',
'OCA\\DAV\\Files\\FilesHome' => $baseDir . '/../lib/Files/FilesHome.php',
'OCA\\DAV\\Files\\HiddenFolderPlugin' => $baseDir . '/../lib/Files/HiddenFolderPlugin.php',
'OCA\\DAV\\Files\\LazySearchBackend' => $baseDir . '/../lib/Files/LazySearchBackend.php',
'OCA\\DAV\\Files\\RootCollection' => $baseDir . '/../lib/Files/RootCollection.php',
'OCA\\DAV\\Files\\Sharing\\FilesDropPlugin' => $baseDir . '/../lib/Files/Sharing/FilesDropPlugin.php',
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Files\\BrowserErrorPagePlugin' => __DIR__ . '/..' . '/../lib/Files/BrowserErrorPagePlugin.php',
'OCA\\DAV\\Files\\FileSearchBackend' => __DIR__ . '/..' . '/../lib/Files/FileSearchBackend.php',
'OCA\\DAV\\Files\\FilesHome' => __DIR__ . '/..' . '/../lib/Files/FilesHome.php',
'OCA\\DAV\\Files\\HiddenFolderPlugin' => __DIR__ . '/..' . '/../lib/Files/HiddenFolderPlugin.php',
'OCA\\DAV\\Files\\LazySearchBackend' => __DIR__ . '/..' . '/../lib/Files/LazySearchBackend.php',
'OCA\\DAV\\Files\\RootCollection' => __DIR__ . '/..' . '/../lib/Files/RootCollection.php',
'OCA\\DAV\\Files\\Sharing\\FilesDropPlugin' => __DIR__ . '/..' . '/../lib/Files/Sharing/FilesDropPlugin.php',
Expand Down
9 changes: 7 additions & 2 deletions apps/dav/lib/Connector/Sabre/Directory.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*/
namespace OCA\DAV\Connector\Sabre;

use OC\Files\Filesystem;
use OC\Files\Mount\MoveableMount;
use OC\Files\View;
use OC\Metadata\FileMetadata;
Expand Down Expand Up @@ -266,10 +267,14 @@ public function getChildren() {
throw new Locked();
}

$hiddenFolderName = Filesystem::getHiddenFolderName();

$nodes = [];
foreach ($folderContent as $info) {
$node = $this->getChild($info->getName(), $info);
$nodes[] = $node;
if ($info->getName() !== $hiddenFolderName) {
$node = $this->getChild($info->getName(), $info);
$nodes[] = $node;
}
}
$this->dirContent = $nodes;
return $this->dirContent;
Expand Down
1 change: 1 addition & 0 deletions apps/dav/lib/Connector/Sabre/ServerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public function createServer(string $baseUri,
$server->addPlugin(new \OCA\DAV\Connector\Sabre\DummyGetResponsePlugin());
$server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
$server->addPlugin(new \OCA\DAV\Files\HiddenFolderPlugin());

$server->addPlugin(new RequestIdHeaderPlugin(\OC::$server->get(IRequest::class)));

Expand Down
44 changes: 44 additions & 0 deletions apps/dav/lib/Files/HiddenFolderPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\DAV\Files;

use OC\Files\Filesystem;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;

class HiddenFolderPlugin extends ServerPlugin {
public function initialize(Server $server): void {
$server->on('beforeBind', [$this, 'onBind'], 1000);
$server->on('beforeUnbind', [$this, 'onBind'], 1000);
}

public function onBind($path): bool {

Check notice

Code scanning / Psalm

MissingParamType

Parameter $path has no provided type
$hiddenName = Filesystem::getHiddenFolderName();
if (basename($path) === $hiddenName) {
throw new Forbidden("Can't modify hidden base folder");
}
return true;
}
}
1 change: 1 addition & 0 deletions apps/dav/lib/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ public function __construct(IRequest $request, string $baseUri) {

$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $logger));
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
$this->server->addPlugin(new \OCA\DAV\Files\HiddenFolderPlugin());
$this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());

// acl
Expand Down
1 change: 1 addition & 0 deletions apps/files/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
'OCA\\Files\\Event\\LoadSidebar' => $baseDir . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => $baseDir . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php',
'OCA\\Files\\Listener\\HiddenFolderListener' => $baseDir . '/../lib/Listener/HiddenFolderListener.php',
'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => $baseDir . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php',
'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files\\Migration\\Version11301Date20191205150729' => $baseDir . '/../lib/Migration/Version11301Date20191205150729.php',
Expand Down
1 change: 1 addition & 0 deletions apps/files/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ComposerStaticInitFiles
'OCA\\Files\\Event\\LoadSidebar' => __DIR__ . '/..' . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => __DIR__ . '/..' . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
'OCA\\Files\\Listener\\HiddenFolderListener' => __DIR__ . '/..' . '/../lib/Listener/HiddenFolderListener.php',
'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => __DIR__ . '/..' . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php',
'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files\\Migration\\Version11301Date20191205150729' => __DIR__ . '/..' . '/../lib/Migration/Version11301Date20191205150729.php',
Expand Down
8 changes: 8 additions & 0 deletions apps/files/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
use OCA\Files\DirectEditingCapabilities;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files\Event\LoadSidebar;
use OCA\Files\Listener\HiddenFolderListener;
use OCA\Files\Listener\LegacyLoadAdditionalScriptsAdapter;
use OCA\Files\Listener\LoadSidebarListener;
use OCA\Files\Notification\Notifier;
Expand All @@ -65,6 +66,7 @@
use OCP\Share\IManager as IShareManager;
use OCP\Util;
use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class Application extends App implements IBootstrap {
public const APP_ID = 'files';
Expand Down Expand Up @@ -131,6 +133,7 @@ public function boot(IBootContext $context): void {
$this->registerTemplates();
$context->injectFn(Closure::fromCallable([$this, 'registerNavigation']));
$this->registerHooks();
$context->injectFn(Closure::fromCallable([$this, 'registerLegacyEvents']));
}

private function registerCollaboration(IProviderManager $providerManager): void {
Expand Down Expand Up @@ -181,4 +184,9 @@ private function registerNavigation(IL10N $l10n): void {
private function registerHooks(): void {
Util::connectHook('\OCP\Config', 'js', '\OCA\Files\App', 'extendJsConfig');
}

private function registerLegacyEvents(EventDispatcherInterface $dispatcher): void {
$listener = new HiddenFolderListener();
$dispatcher->addListener('OCP\Share::preShare', [$listener, 'handlePreShare']);
}
}
44 changes: 44 additions & 0 deletions apps/files/lib/Listener/HiddenFolderListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Files\Listener;

use OC\Files\Filesystem;
use OCP\Share\IShare;
use Symfony\Component\EventDispatcher\GenericEvent;

class HiddenFolderListener {
public function handlePreShare(GenericEvent $event): void {

$share = $event->getSubject();
if (!$share instanceof IShare) {
return;
}

$hiddenName = Filesystem::getHiddenFolderName();
if ($share->getNode()->getName() === $hiddenName) {
$event->stopPropagation();

Check notice

Code scanning / Psalm

DeprecatedMethod

The method Symfony\Component\EventDispatcher\Event::stopPropagation has been marked as deprecated
$event->setArgument("error", "hidden root folder can't be shared");
}
}
}
9 changes: 9 additions & 0 deletions build/integration/features/bootstrap/CommandLine.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,13 @@ public function theCommandOutputContainsTheText($text) {
public function theCommandErrorOutputContainsTheText($text) {
Assert::assertStringContainsString($text, $this->lastStdErr, 'The command did not output the expected text on stderr');
}

/**
* @Given /^system parameter "([^"]*)" is set to "([^"]*)"$/
* @param string $parameter
* @param string $value
*/
public function setSystemConfig(string $parameter, string $value) {
$this->runOcc(['config:system:set', $parameter, '--value', $value]);
}
}
65 changes: 51 additions & 14 deletions build/integration/features/bootstrap/WebDav.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

use Behat\Gherkin\Node\TableNode;
use GuzzleHttp\Client as GClient;
use GuzzleHttp\Message\ResponseInterface;
use PHPUnit\Framework\Assert;
Expand Down Expand Up @@ -273,11 +275,11 @@ public function downloadedContentShouldStartWith($start) {
* @param string $user
* @param string $elementType
* @param string $path
* @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
* @param TableNode|null $propertiesTable
*/
public function asGetsPropertiesOfFolderWith($user, $elementType, $path, $propertiesTable) {
$properties = null;
if ($propertiesTable instanceof \Behat\Gherkin\Node\TableNode) {
if ($propertiesTable instanceof TableNode) {
foreach ($propertiesTable->getRows() as $row) {
$properties[] = $row[0];
}
Expand All @@ -290,7 +292,7 @@ public function asGetsPropertiesOfFolderWith($user, $elementType, $path, $proper
* @param string $user
* @param string $entry
* @param string $path
* @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
* @param TableNode|null $propertiesTable
*/
public function asTheFileOrFolderDoesNotExist($user, $entry, $path) {
$client = $this->getSabreClient($user);
Expand Down Expand Up @@ -574,12 +576,19 @@ public function getSabreClient($user) {

/**
* @Then /^user "([^"]*)" should see following elements$/
* @Then /^user "([^"]*)" should see following elements in folder "([^"]*)"$/
* @param string $user
* @param \Behat\Gherkin\Node\TableNode|null $expectedElements
* @param string|TableNode|null $folder
* @param TableNode|null $expectedElements
*/
public function checkElementList($user, $expectedElements) {
$elementList = $this->listFolder($user, '/', 3);
if ($expectedElements instanceof \Behat\Gherkin\Node\TableNode) {
public function checkElementList($user, $folder, $expectedElements = null) {
if ($folder instanceof TableNode and $expectedElements === null) {
$expectedElements = $folder;
$folder = null;
}
$path = $folder ?? '/';
$elementList = $this->listFolder($user, $path, 3);
if ($expectedElements instanceof TableNode) {
$elementRows = $expectedElements->getRows();
$elementsSimplified = $this->simplifyArray($elementRows);
foreach ($elementsSimplified as $expectedElement) {
Expand All @@ -591,6 +600,34 @@ public function checkElementList($user, $expectedElements) {
}
}

/**
* @Then /^user "([^"]*)" should not see following elements$/
* @param string $user
* @param TableNode|null $expectedElements
*/
public function checkElementNotList($user, $expectedElements) {
try {
$elementList = $this->listFolder($user, '/', 3);
} catch (\Sabre\HTTP\ClientHttpException $e) {
$status = $e->getResponse()->getStatus();
if ($status === 403 || $status === 404) {
// if listing fails the elements are also not listed, so this is fine
return;
}
}

if ($expectedElements instanceof TableNode) {
$elementRows = $expectedElements->getRows();
$elementsSimplified = $this->simplifyArray($elementRows);
foreach ($elementsSimplified as $expectedElement) {
$webdavPath = "/" . $this->getDavFilesPath($user) . $expectedElement;
if (array_key_exists($webdavPath, $elementList)) {
Assert::fail("$webdavPath" . " is in propfind answer");
}
}
}
}

/**
* @When User :user uploads file :source to :destination
* @param string $user
Expand Down Expand Up @@ -622,7 +659,7 @@ public function userAddsAFileTo($user, $bytes, $destination) {
Assert::assertEquals(1, file_exists("work/$filename"));
$this->userUploadsAFileTo($user, "work/$filename", $destination);
$this->removeFile("work/", $filename);
$expectedElements = new \Behat\Gherkin\Node\TableNode([["$destination"]]);
$expectedElements = new TableNode([["$destination"]]);
$this->checkElementList($user, $expectedElements);
}

Expand Down Expand Up @@ -861,7 +898,7 @@ public function changeFavStateOfAnElement($user, $path, $favOrUnfav, $folderDept
* @Given user :user stores etag of element :path
*/
public function userStoresEtagOfElement($user, $path) {
$propertiesTable = new \Behat\Gherkin\Node\TableNode([['{DAV:}getetag']]);
$propertiesTable = new TableNode([['{DAV:}getetag']]);
$this->asGetsPropertiesOfFolderWith($user, 'entry', $path, $propertiesTable);
$pathETAG[$path] = $this->response['{DAV:}getetag'];
$this->storedETAG[$user] = $pathETAG;
Expand All @@ -871,7 +908,7 @@ public function userStoresEtagOfElement($user, $path) {
* @Then etag of element :path of user :user has not changed
*/
public function checkIfETAGHasNotChanged($path, $user) {
$propertiesTable = new \Behat\Gherkin\Node\TableNode([['{DAV:}getetag']]);
$propertiesTable = new TableNode([['{DAV:}getetag']]);
$this->asGetsPropertiesOfFolderWith($user, 'entry', $path, $propertiesTable);
Assert::assertEquals($this->response['{DAV:}getetag'], $this->storedETAG[$user][$path]);
}
Expand All @@ -880,7 +917,7 @@ public function checkIfETAGHasNotChanged($path, $user) {
* @Then etag of element :path of user :user has changed
*/
public function checkIfETAGHasChanged($path, $user) {
$propertiesTable = new \Behat\Gherkin\Node\TableNode([['{DAV:}getetag']]);
$propertiesTable = new TableNode([['{DAV:}getetag']]);
$this->asGetsPropertiesOfFolderWith($user, 'entry', $path, $propertiesTable);
Assert::assertNotEquals($this->response['{DAV:}getetag'], $this->storedETAG[$user][$path]);
}
Expand Down Expand Up @@ -913,14 +950,14 @@ public function thereAreNoDuplicateHeaders() {
* @Then /^user "([^"]*)" in folder "([^"]*)" should have favorited the following elements$/
* @param string $user
* @param string $folder
* @param \Behat\Gherkin\Node\TableNode|null $expectedElements
* @param TableNode|null $expectedElements
*/
public function checkFavoritedElements($user, $folder, $expectedElements) {
$elementList = $this->reportFolder($user,
$folder,
'<oc:favorite/>',
'<oc:favorite>1</oc:favorite>');
if ($expectedElements instanceof \Behat\Gherkin\Node\TableNode) {
if ($expectedElements instanceof TableNode) {
$elementRows = $expectedElements->getRows();
$elementsSimplified = $this->simplifyArray($elementRows);
foreach ($elementsSimplified as $expectedElement) {
Expand Down Expand Up @@ -957,7 +994,7 @@ public function userDeletesEverythingInFolder($user, $folder) {
* @return int
*/
private function getFileIdForPath($user, $path) {
$propertiesTable = new \Behat\Gherkin\Node\TableNode([["{http://owncloud.org/ns}fileid"]]);
$propertiesTable = new TableNode([["{http://owncloud.org/ns}fileid"]]);
$this->asGetsPropertiesOfFolderWith($user, 'file', $path, $propertiesTable);
return (int)$this->response['{http://owncloud.org/ns}fileid'];
}
Expand Down
Loading