aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfenn-cs <fenn25.fn@gmail.com>2024-08-01 17:08:00 +0100
committerfenn-cs <fenn25.fn@gmail.com>2024-08-01 17:08:00 +0100
commitb100be5b7f694125bd9364f97aaccad42d29f0f3 (patch)
treeca730749756b70becf79e00b1eb843e2bee7d5b7
parent0674f6316e03706f3b5070b73d8ba5907c4503f0 (diff)
downloadnextcloud-server-fix/public-copy-move-stable-28.tar.gz
nextcloud-server-fix/public-copy-move-stable-28.zip
WIP: fix(dav): Restore copy/move mechanismfix/public-copy-move-stable-28
Signed-off-by: fenn-cs <fenn25.fn@gmail.com>
-rw-r--r--apps/dav/appinfo/v2/publicremote.php155
-rw-r--r--public.php66
2 files changed, 198 insertions, 23 deletions
diff --git a/apps/dav/appinfo/v2/publicremote.php b/apps/dav/appinfo/v2/publicremote.php
new file mode 100644
index 00000000000..0381614a328
--- /dev/null
+++ b/apps/dav/appinfo/v2/publicremote.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ *
+ * @author Bjoern Schiessle <bjoern@schiessle.org>
+ * @author Björn Schießle <bjoern@schiessle.org>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <vincent@nextcloud.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OC\Files\Filesystem;
+use OC\Files\Storage\Wrapper\PermissionsMask;
+use OC\Files\View;
+use OCA\DAV\Storage\PublicOwnerWrapper;
+use OCA\FederatedFileSharing\FederatedShareProvider;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Mount\IMountManager;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\IPreview;
+use OCP\IRequest;
+use OCP\ISession;
+use OCP\ITagManager;
+use OCP\IUserSession;
+use OCP\L10N\IFactory;
+use OCP\Security\Bruteforce\IThrottler;
+use OCP\Share\IManager;
+use Psr\Log\LoggerInterface;
+use Sabre\DAV\Exception\NotAuthenticated;
+use Sabre\DAV\Exception\NotFound;
+
+// load needed apps
+$RUNTIME_APPTYPES = ['filesystem', 'authentication', 'logging'];
+OC_App::loadApps($RUNTIME_APPTYPES);
+OC_Util::obEnd();
+
+$session = \OCP\Server::get(ISession::class);
+$request = \OCP\Server::get(IRequest::class);
+
+$session->close();
+$requestUri = $request->getRequestUri();
+
+// Backends
+$authBackend = new OCA\DAV\Connector\Sabre\PublicAuth(
+ $request,
+ \OCP\Server::get(IManager::class),
+ $session,
+ \OCP\Server::get(IThrottler::class),
+ \OCP\Server::get(LoggerInterface::class)
+);
+$authPlugin = new \Sabre\DAV\Auth\Plugin($authBackend);
+
+$l10nFactory = \OCP\Server::get(IFactory::class);
+$serverFactory = new OCA\DAV\Connector\Sabre\ServerFactory(
+ \OCP\Server::get(IConfig::class),
+ \OCP\Server::get(LoggerInterface::class),
+ \OCP\Server::get(IDBConnection::class),
+ \OCP\Server::get(IUserSession::class),
+ \OCP\Server::get(IMountManager::class),
+ \OCP\Server::get(ITagManager::class),
+ $request,
+ \OCP\Server::get(IPreview::class),
+ \OCP\Server::get(IEventDispatcher::class),
+ $l10nFactory->get('dav'),
+);
+
+
+$linkCheckPlugin = new \OCA\DAV\Files\Sharing\PublicLinkCheckPlugin();
+$filesDropPlugin = new \OCA\DAV\Files\Sharing\FilesDropPlugin();
+
+// Define root url with /public.php/dav/files/TOKEN
+/** @var string $baseuri defined in public.php */
+preg_match('/(^files\/\w+)/i', substr($requestUri, strlen($baseuri)), $match);
+$baseuri = $baseuri . $match[0];
+
+$server = $serverFactory->createServer($baseuri, $requestUri, $authPlugin, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin, $filesDropPlugin) {
+ $isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? ''));
+ $federatedShareProvider = \OCP\Server::get(FederatedShareProvider::class);
+ if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && !$isAjax) {
+ // this is what is thrown when trying to access a non-existing share
+ throw new NotAuthenticated();
+ }
+
+ $share = $authBackend->getShare();
+ $owner = $share->getShareOwner();
+ $isReadable = $share->getPermissions() & \OCP\Constants::PERMISSION_READ;
+ $fileId = $share->getNodeId();
+
+ // FIXME: should not add storage wrappers outside of preSetup, need to find a better way
+ /** @psalm-suppress InternalMethod */
+ $previousLog = Filesystem::logWarningWhenAddingStorageWrapper(false);
+
+ /** @psalm-suppress MissingClosureParamType */
+ Filesystem::addStorageWrapper('sharePermissions', function ($mountPoint, $storage) use ($share) {
+ return new PermissionsMask(['storage' => $storage, 'mask' => $share->getPermissions() | \OCP\Constants::PERMISSION_SHARE]);
+ });
+
+ /** @psalm-suppress MissingClosureParamType */
+ Filesystem::addStorageWrapper('shareOwner', function ($mountPoint, $storage) use ($share) {
+ return new PublicOwnerWrapper(['storage' => $storage, 'owner' => $share->getShareOwner()]);
+ });
+
+ /** @psalm-suppress InternalMethod */
+ Filesystem::logWarningWhenAddingStorageWrapper($previousLog);
+
+ OC_Util::tearDownFS();
+ OC_Util::setupFS($owner);
+ $ownerView = new View('/'. $owner . '/files');
+ $path = $ownerView->getPath($fileId);
+ $fileInfo = $ownerView->getFileInfo($path);
+
+ if ($fileInfo === false) {
+ throw new NotFound();
+ }
+
+ $linkCheckPlugin->setFileInfo($fileInfo);
+
+ // If not readble (files_drop) enable the filesdrop plugin
+ if (!$isReadable) {
+ $filesDropPlugin->enable();
+ }
+
+ $view = new View($ownerView->getAbsolutePath($path));
+ $filesDropPlugin->setView($view);
+
+ return $view;
+});
+
+$server->addPlugin($linkCheckPlugin);
+$server->addPlugin($filesDropPlugin);
+
+// And off we go!
+$server->exec();
diff --git a/public.php b/public.php
index 2956d7f79dd..2bf710c72fc 100644
--- a/public.php
+++ b/public.php
@@ -32,33 +32,55 @@
*/
require_once __DIR__ . '/lib/versioncheck.php';
+use Psr\Log\LoggerInterface;
+
+/**
+ * @param $service
+ * @return string
+ */
+function resolveService(string $service): string {
+ $services = [
+ 'webdav' => 'dav/appinfo/v1/publicwebdav.php',
+ 'dav' => 'dav/appinfo/v2/publicremote.php',
+ ];
+ if (isset($services[$service])) {
+ return $services[$service];
+ }
+
+ return \OC::$server->getConfig()->getAppValue('core', 'remote_' . $service);
+}
+
try {
require_once __DIR__ . '/lib/base.php';
+
+ // All resources served via the DAV endpoint should have the strictest possible
+ // policy. Exempted from this is the SabreDAV browser plugin which overwrites
+ // this policy with a softer one if debug mode is enabled.
+ header("Content-Security-Policy: default-src 'none';");
+
if (\OCP\Util::needUpgrade()) {
// since the behavior of apps or remotes are unpredictable during
// an upgrade, return a 503 directly
- OC_Template::printErrorPage('Service unavailable', '', 503);
- exit;
+ throw new RemoteException('Service unavailable', 503);
}
- OC::checkMaintenanceMode(\OC::$server->get(\OC\SystemConfig::class));
$request = \OC::$server->getRequest();
$pathInfo = $request->getPathInfo();
-
- if (!$pathInfo && $request->getParam('service', '') === '') {
- http_response_code(404);
- exit;
- } elseif ($request->getParam('service', '')) {
- $service = $request->getParam('service', '');
- } else {
- $pathInfo = trim($pathInfo, '/');
- [$service] = explode('/', $pathInfo);
+ if ($pathInfo === false || $pathInfo === '') {
+ throw new RemoteException('Path not found', 404);
}
- $file = \OC::$server->getConfig()->getAppValue('core', 'public_' . strip_tags($service));
- if ($file === '') {
- http_response_code(404);
- exit;
+ if (!$pos = strpos($pathInfo, '/', 1)) {
+ $pos = strlen($pathInfo);
}
+ $service = substr($pathInfo, 1, $pos - 1);
+
+ $file = resolveService($service);
+
+ if (!$file) {
+ throw new RemoteException('Path not found', 404);
+ }
+
+ $file = ltrim($file, '/');
$parts = explode('/', $file, 2);
$app = $parts[0];
@@ -70,25 +92,23 @@ try {
OC_App::loadApps(['filesystem', 'logging']);
if (!\OC::$server->getAppManager()->isInstalled($app)) {
- http_response_code(404);
- exit;
+ throw new RemoteException('App not installed: ' . $app);
}
OC_App::loadApp($app);
OC_User::setIncognitoMode(true);
- $baseuri = OC::$WEBROOT . '/public.php/' . $service . '/';
-
- require_once OC_App::getAppPath($app) . '/' . $parts[1];
+ $baseuri = OC::$WEBROOT . '/public.php/'.$service.'/';
+ require_once $file;
} catch (Exception $ex) {
$status = 500;
if ($ex instanceof \OC\ServiceUnavailableException) {
$status = 503;
}
//show the user a detailed error page
- \OC::$server->getLogger()->logException($ex, ['app' => 'public']);
+ \OCP\Server::get(LoggerInterface::class)->error($ex->getMessage(), ['app' => 'public', 'exception' => $ex]);
OC_Template::printExceptionErrorPage($ex, $status);
} catch (Error $ex) {
//show the user a detailed error page
- \OC::$server->getLogger()->logException($ex, ['app' => 'public']);
+ \OCP\Server::get(LoggerInterface::class)->error($ex->getMessage(), ['app' => 'public', 'exception' => $ex]);
OC_Template::printExceptionErrorPage($ex, 500);
}