diff options
author | Joas Schilling <nickvergessen@gmx.de> | 2016-05-12 09:42:40 +0200 |
---|---|---|
committer | Thomas Müller <DeepDiver1975@users.noreply.github.com> | 2016-05-12 09:42:40 +0200 |
commit | dd9ee10bc0699e5dcc17c3ef2181dcda01d9a69b (patch) | |
tree | 2d464fcc20ea330481e56487287aeae462ce5917 /apps/dav/lib/connector/sabre | |
parent | 4a3311f430ec6e45c62b2ebde2cae71e943f3c81 (diff) | |
download | nextcloud-server-dd9ee10bc0699e5dcc17c3ef2181dcda01d9a69b.tar.gz nextcloud-server-dd9ee10bc0699e5dcc17c3ef2181dcda01d9a69b.zip |
Move dav app to PSR-4 (#24527)
* Move Application to correct namespace and PSR-4 it
* Move dav app to PSR-4
Diffstat (limited to 'apps/dav/lib/connector/sabre')
32 files changed, 0 insertions, 5412 deletions
diff --git a/apps/dav/lib/connector/sabre/appenabledplugin.php b/apps/dav/lib/connector/sabre/appenabledplugin.php deleted file mode 100644 index cb061d6a309..00000000000 --- a/apps/dav/lib/connector/sabre/appenabledplugin.php +++ /dev/null @@ -1,90 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\App\IAppManager; -use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\ServerPlugin; - -/** - * Plugin to check if an app is enabled for the current user - */ -class AppEnabledPlugin extends ServerPlugin { - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var string - */ - private $app; - - /** - * @var \OCP\App\IAppManager - */ - private $appManager; - - /** - * @param string $app - * @param \OCP\App\IAppManager $appManager - */ - public function __construct($app, IAppManager $appManager) { - $this->app = $app; - $this->appManager = $appManager; - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - - $this->server = $server; - $this->server->on('beforeMethod', array($this, 'checkAppEnabled'), 30); - } - - /** - * This method is called before any HTTP after auth and checks if the user has access to the app - * - * @throws \Sabre\DAV\Exception\Forbidden - * @return bool - */ - public function checkAppEnabled() { - if (!$this->appManager->isEnabledForUser($this->app)) { - throw new Forbidden(); - } - } -} diff --git a/apps/dav/lib/connector/sabre/auth.php b/apps/dav/lib/connector/sabre/auth.php deleted file mode 100644 index b8047e779f5..00000000000 --- a/apps/dav/lib/connector/sabre/auth.php +++ /dev/null @@ -1,229 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Jakob Sack <mail@jakobsack.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Markus Goetz <markus@woboq.com> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre; - -use Exception; -use OC\AppFramework\Http\Request; -use OCP\IRequest; -use OCP\ISession; -use OC\User\Session; -use Sabre\DAV\Auth\Backend\AbstractBasic; -use Sabre\DAV\Exception\NotAuthenticated; -use Sabre\DAV\Exception\ServiceUnavailable; -use Sabre\HTTP\RequestInterface; -use Sabre\HTTP\ResponseInterface; - -class Auth extends AbstractBasic { - const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND'; - - /** @var ISession */ - private $session; - /** @var Session */ - private $userSession; - /** @var IRequest */ - private $request; - /** @var string */ - private $currentUser; - - /** - * @param ISession $session - * @param Session $userSession - * @param IRequest $request - * @param string $principalPrefix - */ - public function __construct(ISession $session, - Session $userSession, - IRequest $request, - $principalPrefix = 'principals/users/') { - $this->session = $session; - $this->userSession = $userSession; - $this->request = $request; - $this->principalPrefix = $principalPrefix; - } - - /** - * Whether the user has initially authenticated via DAV - * - * This is required for WebDAV clients that resent the cookies even when the - * account was changed. - * - * @see https://github.com/owncloud/core/issues/13245 - * - * @param string $username - * @return bool - */ - public function isDavAuthenticated($username) { - return !is_null($this->session->get(self::DAV_AUTHENTICATED)) && - $this->session->get(self::DAV_AUTHENTICATED) === $username; - } - - /** - * Validates a username and password - * - * This method should return true or false depending on if login - * succeeded. - * - * @param string $username - * @param string $password - * @return bool - */ - protected function validateUserPass($username, $password) { - if ($this->userSession->isLoggedIn() && - $this->isDavAuthenticated($this->userSession->getUser()->getUID()) - ) { - \OC_Util::setupFS($this->userSession->getUser()->getUID()); - $this->session->close(); - return true; - } else { - \OC_Util::setUpFS(); //login hooks may need early access to the filesystem - if($this->userSession->login($username, $password)) { - $this->userSession->createSessionToken($this->request, $username, $password); - \OC_Util::setUpFS($this->userSession->getUser()->getUID()); - $this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID()); - $this->session->close(); - return true; - } else { - $this->session->close(); - return false; - } - } - } - - /** - * @param RequestInterface $request - * @param ResponseInterface $response - * @return array - * @throws NotAuthenticated - * @throws ServiceUnavailable - */ - function check(RequestInterface $request, ResponseInterface $response) { - try { - $result = $this->auth($request, $response); - return $result; - } catch (NotAuthenticated $e) { - throw $e; - } catch (Exception $e) { - $class = get_class($e); - $msg = $e->getMessage(); - throw new ServiceUnavailable("$class: $msg"); - } - } - - /** - * Checks whether a CSRF check is required on the request - * - * @return bool - */ - private function requiresCSRFCheck() { - // GET requires no check at all - if($this->request->getMethod() === 'GET') { - return false; - } - - // Official ownCloud clients require no checks - if($this->request->isUserAgent([ - Request::USER_AGENT_OWNCLOUD_DESKTOP, - Request::USER_AGENT_OWNCLOUD_ANDROID, - Request::USER_AGENT_OWNCLOUD_IOS, - ])) { - return false; - } - - // If not logged-in no check is required - if(!$this->userSession->isLoggedIn()) { - return false; - } - - // POST always requires a check - if($this->request->getMethod() === 'POST') { - return true; - } - - // If logged-in AND DAV authenticated no check is required - if($this->userSession->isLoggedIn() && - $this->isDavAuthenticated($this->userSession->getUser()->getUID())) { - return false; - } - - return true; - } - - /** - * @param RequestInterface $request - * @param ResponseInterface $response - * @return array - * @throws NotAuthenticated - */ - private function auth(RequestInterface $request, ResponseInterface $response) { - $forcedLogout = false; - if(!$this->request->passesCSRFCheck() && - $this->requiresCSRFCheck()) { - // In case of a fail with POST we need to recheck the credentials - if($this->request->getMethod() === 'POST') { - $forcedLogout = true; - } else { - $response->setStatus(401); - throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.'); - } - } - - if($forcedLogout) { - $this->userSession->logout(); - } else { - if (\OC_User::handleApacheAuth() || - //Fix for broken webdav clients - ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) || - //Well behaved clients that only send the cookie are allowed - ($this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null) - ) { - $user = $this->userSession->getUser()->getUID(); - \OC_Util::setupFS($user); - $this->currentUser = $user; - $this->session->close(); - return [true, $this->principalPrefix . $user]; - } - } - - if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) { - // do not re-authenticate over ajax, use dummy auth name to prevent browser popup - $response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"'); - $response->setStatus(401); - throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls'); - } - - $data = parent::check($request, $response); - if($data[0] === true) { - $startPos = strrpos($data[1], '/') + 1; - $user = $this->userSession->getUser()->getUID(); - $data[1] = substr_replace($data[1], $user, $startPos); - } - return $data; - } -} diff --git a/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php b/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php deleted file mode 100644 index 70d19cb7f2a..00000000000 --- a/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\IConfig; -use Sabre\HTTP\RequestInterface; -use Sabre\DAV\ServerPlugin; -use Sabre\DAV\Exception; - -/** - * Class BlockLegacyClientPlugin is used to detect old legacy sync clients and - * returns a 403 status to those clients - * - * @package OCA\DAV\Connector\Sabre - */ -class BlockLegacyClientPlugin extends ServerPlugin { - /** @var \Sabre\DAV\Server */ - protected $server; - /** @var IConfig */ - protected $config; - - /** - * @param IConfig $config - */ - public function __construct(IConfig $config) { - $this->config = $config; - } - - /** - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - $this->server = $server; - $this->server->on('beforeMethod', [$this, 'beforeHandler'], 200); - } - - /** - * Detects all unsupported clients and throws a \Sabre\DAV\Exception\Forbidden - * exception which will result in a 403 to them. - * @param RequestInterface $request - * @throws \Sabre\DAV\Exception\Forbidden If the client version is not supported - */ - public function beforeHandler(RequestInterface $request) { - $userAgent = $request->getHeader('User-Agent'); - if($userAgent === null) { - return; - } - - $minimumSupportedDesktopVersion = $this->config->getSystemValue('minimum.supported.desktop.version', '1.7.0'); - - // Match on the mirall version which is in scheme "Mozilla/5.0 (%1) mirall/%2" or - // "mirall/%1" for older releases - preg_match("/(?:mirall\\/)([\d.]+)/i", $userAgent, $versionMatches); - if(isset($versionMatches[1]) && - version_compare($versionMatches[1], $minimumSupportedDesktopVersion) === -1) { - throw new \Sabre\DAV\Exception\Forbidden('Unsupported client version.'); - } - } -} diff --git a/apps/dav/lib/connector/sabre/checksumlist.php b/apps/dav/lib/connector/sabre/checksumlist.php deleted file mode 100644 index f137222acca..00000000000 --- a/apps/dav/lib/connector/sabre/checksumlist.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php -/** - * @author Roeland Jago Douma <rullzer@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre; - -use Sabre\Xml\XmlSerializable; -use Sabre\Xml\Element; -use Sabre\Xml\Writer; - -/** - * Checksumlist property - * - * This property contains multiple "checksum" elements, each containing a - * checksum name. - */ -class ChecksumList implements XmlSerializable { - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - - /** @var string[] of TYPE:CHECKSUM */ - private $checksums; - - /** - * @param string $checksum - */ - public function __construct($checksum) { - $this->checksums = explode(',', $checksum); - } - - /** - * The xmlSerialize metod is called during xml writing. - * - * Use the $writer argument to write its own xml serialization. - * - * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered - * its 'inner xml'. - * - * The parent of the current element is responsible for writing a - * containing element. - * - * This allows serializers to be re-used for different element names. - * - * If you are opening new elements, you must also close them again. - * - * @param Writer $writer - * @return void - */ - function xmlSerialize(Writer $writer) { - - foreach ($this->checksums as $checksum) { - $writer->writeElement('{' . self::NS_OWNCLOUD . '}checksum', $checksum); - } - } -} diff --git a/apps/dav/lib/connector/sabre/commentpropertiesplugin.php b/apps/dav/lib/connector/sabre/commentpropertiesplugin.php deleted file mode 100644 index a8d5f771122..00000000000 --- a/apps/dav/lib/connector/sabre/commentpropertiesplugin.php +++ /dev/null @@ -1,130 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\Comments\ICommentsManager; -use OCP\IUserSession; -use Sabre\DAV\PropFind; -use Sabre\DAV\ServerPlugin; - -class CommentPropertiesPlugin extends ServerPlugin { - - const PROPERTY_NAME_HREF = '{http://owncloud.org/ns}comments-href'; - const PROPERTY_NAME_COUNT = '{http://owncloud.org/ns}comments-count'; - const PROPERTY_NAME_UNREAD = '{http://owncloud.org/ns}comments-unread'; - - /** @var \Sabre\DAV\Server */ - protected $server; - - /** @var ICommentsManager */ - private $commentsManager; - - /** @var IUserSession */ - private $userSession; - - public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) { - $this->commentsManager = $commentsManager; - $this->userSession = $userSession; - } - - /** - * This initializes the plugin. - * - * This function is called by Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - function initialize(\Sabre\DAV\Server $server) { - $this->server = $server; - $this->server->on('propFind', array($this, 'handleGetProperties')); - } - - /** - * Adds tags and favorites properties to the response, - * if requested. - * - * @param PropFind $propFind - * @param \Sabre\DAV\INode $node - * @return void - */ - public function handleGetProperties( - PropFind $propFind, - \Sabre\DAV\INode $node - ) { - if (!($node instanceof File) && !($node instanceof Directory)) { - return; - } - - $propFind->handle(self::PROPERTY_NAME_COUNT, function() use ($node) { - return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId())); - }); - - $propFind->handle(self::PROPERTY_NAME_HREF, function() use ($node) { - return $this->getCommentsLink($node); - }); - - $propFind->handle(self::PROPERTY_NAME_UNREAD, function() use ($node) { - return $this->getUnreadCount($node); - }); - } - - /** - * returns a reference to the comments node - * - * @param Node $node - * @return mixed|string - */ - public function getCommentsLink(Node $node) { - $href = $this->server->getBaseUri(); - $entryPoint = strrpos($href, '/webdav/'); - if($entryPoint === false) { - // in case we end up somewhere else, unexpectedly. - return null; - } - $href = substr_replace($href, '/dav/', $entryPoint); - $href .= 'comments/files/' . rawurldecode($node->getId()); - return $href; - } - - /** - * returns the number of unread comments for the currently logged in user - * on the given file or directory node - * - * @param Node $node - * @return Int|null - */ - public function getUnreadCount(Node $node) { - $user = $this->userSession->getUser(); - if(is_null($user)) { - return null; - } - - $lastRead = $this->commentsManager->getReadMark('files', strval($node->getId()), $user); - - return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()), $lastRead); - } - -} diff --git a/apps/dav/lib/connector/sabre/copyetagheaderplugin.php b/apps/dav/lib/connector/sabre/copyetagheaderplugin.php deleted file mode 100644 index 49b6a7b2de7..00000000000 --- a/apps/dav/lib/connector/sabre/copyetagheaderplugin.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use \Sabre\HTTP\RequestInterface; -use \Sabre\HTTP\ResponseInterface; - -/** - * Copies the "Etag" header to "OC-Etag" after any request. - * This is a workaround for setups that automatically strip - * or mangle Etag headers. - */ -class CopyEtagHeaderPlugin extends \Sabre\DAV\ServerPlugin { - /** - * This initializes the plugin. - * - * @param \Sabre\DAV\Server $server Sabre server - * - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - $server->on('afterMethod', array($this, 'afterMethod')); - } - - /** - * After method, copy the "Etag" header to "OC-Etag" header. - * - * @param RequestInterface $request request - * @param ResponseInterface $response response - */ - public function afterMethod(RequestInterface $request, ResponseInterface $response) { - $eTag = $response->getHeader('Etag'); - if (!empty($eTag)) { - $response->setHeader('OC-ETag', $eTag); - } - } -} diff --git a/apps/dav/lib/connector/sabre/custompropertiesbackend.php b/apps/dav/lib/connector/sabre/custompropertiesbackend.php deleted file mode 100644 index 5946c9910d4..00000000000 --- a/apps/dav/lib/connector/sabre/custompropertiesbackend.php +++ /dev/null @@ -1,355 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\IDBConnection; -use OCP\IUser; -use Sabre\DAV\PropertyStorage\Backend\BackendInterface; -use Sabre\DAV\PropFind; -use Sabre\DAV\PropPatch; -use Sabre\DAV\Tree; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\ServiceUnavailable; - -class CustomPropertiesBackend implements BackendInterface { - - /** - * Ignored properties - * - * @var array - */ - private $ignoredProperties = array( - '{DAV:}getcontentlength', - '{DAV:}getcontenttype', - '{DAV:}getetag', - '{DAV:}quota-used-bytes', - '{DAV:}quota-available-bytes', - '{DAV:}quota-available-bytes', - '{http://owncloud.org/ns}permissions', - '{http://owncloud.org/ns}downloadURL', - '{http://owncloud.org/ns}dDC', - '{http://owncloud.org/ns}size', - ); - - /** - * @var Tree - */ - private $tree; - - /** - * @var IDBConnection - */ - private $connection; - - /** - * @var IUser - */ - private $user; - - /** - * Properties cache - * - * @var array - */ - private $cache = []; - - /** - * @param Tree $tree node tree - * @param IDBConnection $connection database connection - * @param IUser $user owner of the tree and properties - */ - public function __construct( - Tree $tree, - IDBConnection $connection, - IUser $user) { - $this->tree = $tree; - $this->connection = $connection; - $this->user = $user->getUID(); - } - - /** - * Fetches properties for a path. - * - * @param string $path - * @param PropFind $propFind - * @return void - */ - public function propFind($path, PropFind $propFind) { - try { - $node = $this->tree->getNodeForPath($path); - if (!($node instanceof Node)) { - return; - } - } catch (ServiceUnavailable $e) { - // might happen for unavailable mount points, skip - return; - } catch (NotFound $e) { - // in some rare (buggy) cases the node might not be found, - // we catch the exception to prevent breaking the whole list with a 404 - // (soft fail) - \OC::$server->getLogger()->warning( - 'Could not get node for path: \"' . $path . '\" : ' . $e->getMessage(), - array('app' => 'files') - ); - return; - } - - $requestedProps = $propFind->get404Properties(); - - // these might appear - $requestedProps = array_diff( - $requestedProps, - $this->ignoredProperties - ); - - if (empty($requestedProps)) { - return; - } - - if ($node instanceof Directory - && $propFind->getDepth() !== 0 - ) { - // note: pre-fetching only supported for depth <= 1 - $this->loadChildrenProperties($node, $requestedProps); - } - - $props = $this->getProperties($node, $requestedProps); - foreach ($props as $propName => $propValue) { - $propFind->set($propName, $propValue); - } - } - - /** - * Updates properties for a path - * - * @param string $path - * @param PropPatch $propPatch - * - * @return void - */ - public function propPatch($path, PropPatch $propPatch) { - $node = $this->tree->getNodeForPath($path); - if (!($node instanceof Node)) { - return; - } - - $propPatch->handleRemaining(function($changedProps) use ($node) { - return $this->updateProperties($node, $changedProps); - }); - } - - /** - * This method is called after a node is deleted. - * - * @param string $path path of node for which to delete properties - */ - public function delete($path) { - $statement = $this->connection->prepare( - 'DELETE FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?' - ); - $statement->execute(array($this->user, '/' . $path)); - $statement->closeCursor(); - - unset($this->cache[$path]); - } - - /** - * This method is called after a successful MOVE - * - * @param string $source - * @param string $destination - * - * @return void - */ - public function move($source, $destination) { - $statement = $this->connection->prepare( - 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' . - ' WHERE `userid` = ? AND `propertypath` = ?' - ); - $statement->execute(array('/' . $destination, $this->user, '/' . $source)); - $statement->closeCursor(); - } - - /** - * Returns a list of properties for this nodes.; - * @param Node $node - * @param array $requestedProperties requested properties or empty array for "all" - * @return array - * @note The properties list is a list of propertynames the client - * requested, encoded as xmlnamespace#tagName, for example: - * http://www.example.org/namespace#author If the array is empty, all - * properties should be returned - */ - private function getProperties(Node $node, array $requestedProperties) { - $path = $node->getPath(); - if (isset($this->cache[$path])) { - return $this->cache[$path]; - } - - // TODO: chunking if more than 1000 properties - $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'; - - $whereValues = array($this->user, $path); - $whereTypes = array(null, null); - - if (!empty($requestedProperties)) { - // request only a subset - $sql .= ' AND `propertyname` in (?)'; - $whereValues[] = $requestedProperties; - $whereTypes[] = \Doctrine\DBAL\Connection::PARAM_STR_ARRAY; - } - - $result = $this->connection->executeQuery( - $sql, - $whereValues, - $whereTypes - ); - - $props = []; - while ($row = $result->fetch()) { - $props[$row['propertyname']] = $row['propertyvalue']; - } - - $result->closeCursor(); - - $this->cache[$path] = $props; - return $props; - } - - /** - * Update properties - * - * @param Node $node node for which to update properties - * @param array $properties array of properties to update - * - * @return bool - */ - private function updateProperties($node, $properties) { - $path = $node->getPath(); - - $deleteStatement = 'DELETE FROM `*PREFIX*properties`' . - ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; - - $insertStatement = 'INSERT INTO `*PREFIX*properties`' . - ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'; - - $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' . - ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; - - // TODO: use "insert or update" strategy ? - $existing = $this->getProperties($node, array()); - $this->connection->beginTransaction(); - foreach ($properties as $propertyName => $propertyValue) { - // If it was null, we need to delete the property - if (is_null($propertyValue)) { - if (array_key_exists($propertyName, $existing)) { - $this->connection->executeUpdate($deleteStatement, - array( - $this->user, - $path, - $propertyName - ) - ); - } - } else { - if (!array_key_exists($propertyName, $existing)) { - $this->connection->executeUpdate($insertStatement, - array( - $this->user, - $path, - $propertyName, - $propertyValue - ) - ); - } else { - $this->connection->executeUpdate($updateStatement, - array( - $propertyValue, - $this->user, - $path, - $propertyName - ) - ); - } - } - } - - $this->connection->commit(); - unset($this->cache[$path]); - - return true; - } - - /** - * Bulk load properties for directory children - * - * @param Directory $node - * @param array $requestedProperties requested properties - * - * @return void - */ - private function loadChildrenProperties(Directory $node, $requestedProperties) { - $path = $node->getPath(); - if (isset($this->cache[$path])) { - // we already loaded them at some point - return; - } - - $childNodes = $node->getChildren(); - // pre-fill cache - foreach ($childNodes as $childNode) { - $this->cache[$childNode->getPath()] = []; - } - - $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` LIKE ?'; - $sql .= ' AND `propertyname` in (?) ORDER BY `propertypath`, `propertyname`'; - - $result = $this->connection->executeQuery( - $sql, - array($this->user, rtrim($path, '/') . '/%', $requestedProperties), - array(null, null, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY) - ); - - $oldPath = null; - $props = []; - while ($row = $result->fetch()) { - $path = $row['propertypath']; - if ($oldPath !== $path) { - // save previously gathered props - $this->cache[$oldPath] = $props; - $oldPath = $path; - // prepare props for next path - $props = []; - } - $props[$row['propertyname']] = $row['propertyvalue']; - } - if (!is_null($oldPath)) { - // save props from last run - $this->cache[$oldPath] = $props; - } - - $result->closeCursor(); - } - -} diff --git a/apps/dav/lib/connector/sabre/davaclplugin.php b/apps/dav/lib/connector/sabre/davaclplugin.php deleted file mode 100644 index f5699b469c3..00000000000 --- a/apps/dav/lib/connector/sabre/davaclplugin.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\IFile; -use Sabre\DAV\INode; -use \Sabre\DAV\PropFind; -use \Sabre\DAV\PropPatch; -use Sabre\DAVACL\Exception\NeedPrivileges; -use \Sabre\HTTP\RequestInterface; -use \Sabre\HTTP\ResponseInterface; -use Sabre\HTTP\URLUtil; - -/** - * Class DavAclPlugin is a wrapper around \Sabre\DAVACL\Plugin that returns 404 - * responses in case the resource to a response has been forbidden instead of - * a 403. This is used to prevent enumeration of valid resources. - * - * @see https://github.com/owncloud/core/issues/22578 - * @package OCA\DAV\Connector\Sabre - */ -class DavAclPlugin extends \Sabre\DAVACL\Plugin { - public function __construct() { - $this->hideNodesFromListings = true; - } - - function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) { - $access = parent::checkPrivileges($uri, $privileges, $recursion, false); - if($access === false && $throwExceptions) { - /** @var INode $node */ - $node = $this->server->tree->getNodeForPath($uri); - - switch(get_class($node)) { - case 'OCA\DAV\CardDAV\AddressBook': - $type = 'Addressbook'; - break; - default: - $type = 'Node'; - break; - } - throw new NotFound( - sprintf( - "%s with name '%s' could not be found", - $type, - $node->getName() - ) - ); - } - - return $access; - } -} diff --git a/apps/dav/lib/connector/sabre/directory.php b/apps/dav/lib/connector/sabre/directory.php deleted file mode 100644 index daa5f29ce79..00000000000 --- a/apps/dav/lib/connector/sabre/directory.php +++ /dev/null @@ -1,310 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Jakob Sack <mail@jakobsack.de> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre; - -use OCA\DAV\Connector\Sabre\Exception\Forbidden; -use OCA\DAV\Connector\Sabre\Exception\InvalidPath; -use OCA\DAV\Connector\Sabre\Exception\FileLocked; -use OCP\Files\ForbiddenException; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; -use Sabre\DAV\Exception\Locked; - -class Directory extends \OCA\DAV\Connector\Sabre\Node - implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota { - - /** - * Cached directory content - * - * @var \OCP\Files\FileInfo[] - */ - private $dirContent; - - /** - * Cached quota info - * - * @var array - */ - private $quotaInfo; - - /** - * @var ObjectTree|null - */ - private $tree; - - /** - * Sets up the node, expects a full path name - * - * @param \OC\Files\View $view - * @param \OCP\Files\FileInfo $info - * @param ObjectTree|null $tree - * @param \OCP\Share\IManager $shareManager - */ - public function __construct($view, $info, $tree = null, $shareManager = null) { - parent::__construct($view, $info, $shareManager); - $this->tree = $tree; - } - - /** - * Creates a new file in the directory - * - * Data will either be supplied as a stream resource, or in certain cases - * as a string. Keep in mind that you may have to support either. - * - * After successful creation of the file, you may choose to return the ETag - * of the new file here. - * - * The returned ETag must be surrounded by double-quotes (The quotes should - * be part of the actual string). - * - * If you cannot accurately determine the ETag, you should not return it. - * If you don't store the file exactly as-is (you're transforming it - * somehow) you should also not return an ETag. - * - * This means that if a subsequent GET to this new file does not exactly - * return the same contents of what was submitted here, you are strongly - * recommended to omit the ETag. - * - * @param string $name Name of the file - * @param resource|string $data Initial payload - * @return null|string - * @throws Exception\EntityTooLarge - * @throws Exception\UnsupportedMediaType - * @throws FileLocked - * @throws InvalidPath - * @throws \Sabre\DAV\Exception - * @throws \Sabre\DAV\Exception\BadRequest - * @throws \Sabre\DAV\Exception\Forbidden - * @throws \Sabre\DAV\Exception\ServiceUnavailable - */ - public function createFile($name, $data = null) { - - try { - // for chunked upload also updating a existing file is a "createFile" - // because we create all the chunks before re-assemble them to the existing file. - if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - - // exit if we can't create a new file and we don't updatable existing file - $info = \OC_FileChunking::decodeName($name); - if (!$this->fileView->isCreatable($this->path) && - !$this->fileView->isUpdatable($this->path . '/' . $info['name']) - ) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - - } else { - // For non-chunked upload it is enough to check if we can create a new file - if (!$this->fileView->isCreatable($this->path)) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - } - - $this->fileView->verifyPath($this->path, $name); - - $path = $this->fileView->getAbsolutePath($this->path) . '/' . $name; - // using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete - $info = new \OC\Files\FileInfo($path, null, null, array(), null); - $node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info); - $node->acquireLock(ILockingProvider::LOCK_SHARED); - return $node->put($data); - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } catch (ForbiddenException $ex) { - throw new Forbidden($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Creates a new subdirectory - * - * @param string $name - * @throws FileLocked - * @throws InvalidPath - * @throws \Sabre\DAV\Exception\Forbidden - * @throws \Sabre\DAV\Exception\ServiceUnavailable - */ - public function createDirectory($name) { - try { - if (!$this->info->isCreatable()) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - - $this->fileView->verifyPath($this->path, $name); - $newPath = $this->path . '/' . $name; - if (!$this->fileView->mkdir($newPath)) { - throw new \Sabre\DAV\Exception\Forbidden('Could not create directory ' . $newPath); - } - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } catch (ForbiddenException $ex) { - throw new Forbidden($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Returns a specific child node, referenced by its name - * - * @param string $name - * @param \OCP\Files\FileInfo $info - * @return \Sabre\DAV\INode - * @throws InvalidPath - * @throws \Sabre\DAV\Exception\NotFound - * @throws \Sabre\DAV\Exception\ServiceUnavailable - */ - public function getChild($name, $info = null) { - $path = $this->path . '/' . $name; - if (is_null($info)) { - try { - $this->fileView->verifyPath($this->path, $name); - $info = $this->fileView->getFileInfo($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } - } - - if (!$info) { - throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located'); - } - - if ($info['mimetype'] == 'httpd/unix-directory') { - $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this->tree, $this->shareManager); - } else { - $node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info, $this->shareManager); - } - if ($this->tree) { - $this->tree->cacheNode($node); - } - return $node; - } - - /** - * Returns an array with all the child nodes - * - * @return \Sabre\DAV\INode[] - */ - public function getChildren() { - if (!is_null($this->dirContent)) { - return $this->dirContent; - } - try { - $folderContent = $this->fileView->getDirectoryContent($this->path); - } catch (LockedException $e) { - throw new Locked(); - } - - $nodes = array(); - foreach ($folderContent as $info) { - $node = $this->getChild($info->getName(), $info); - $nodes[] = $node; - } - $this->dirContent = $nodes; - return $this->dirContent; - } - - /** - * Checks if a child exists. - * - * @param string $name - * @return bool - */ - public function childExists($name) { - // note: here we do NOT resolve the chunk file name to the real file name - // to make sure we return false when checking for file existence with a chunk - // file name. - // This is to make sure that "createFile" is still triggered - // (required old code) instead of "updateFile". - // - // TODO: resolve chunk file name here and implement "updateFile" - $path = $this->path . '/' . $name; - return $this->fileView->file_exists($path); - - } - - /** - * Deletes all files in this directory, and then itself - * - * @return void - * @throws FileLocked - * @throws \Sabre\DAV\Exception\Forbidden - */ - public function delete() { - - if ($this->path === '' || $this->path === '/' || !$this->info->isDeletable()) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - - try { - if (!$this->fileView->rmdir($this->path)) { - // assume it wasn't possible to remove due to permission issue - throw new \Sabre\DAV\Exception\Forbidden(); - } - } catch (ForbiddenException $ex) { - throw new Forbidden($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Returns available diskspace information - * - * @return array - */ - public function getQuotaInfo() { - if ($this->quotaInfo) { - return $this->quotaInfo; - } - try { - $storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $this->info); - if ($storageInfo['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED) { - $free = \OCP\Files\FileInfo::SPACE_UNLIMITED; - } else { - $free = $storageInfo['free']; - } - $this->quotaInfo = array( - $storageInfo['used'], - $free - ); - return $this->quotaInfo; - } catch (\OCP\Files\StorageNotAvailableException $e) { - return array(0, 0); - } - } - -} diff --git a/apps/dav/lib/connector/sabre/dummygetresponseplugin.php b/apps/dav/lib/connector/sabre/dummygetresponseplugin.php deleted file mode 100644 index b10d5aaab36..00000000000 --- a/apps/dav/lib/connector/sabre/dummygetresponseplugin.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; -use Sabre\HTTP\ResponseInterface; -use Sabre\HTTP\RequestInterface; - -/** - * Class DummyGetResponsePlugin is a plugin used to not show a "Not implemented" - * error to clients that rely on verifying the functionality of the ownCloud - * WebDAV backend using a simple GET to /. - * - * This is considered a legacy behaviour and implementers should consider sending - * a PROPFIND request instead to verify whether the WebDAV component is working - * properly. - * - * FIXME: Remove once clients are all compliant. - * - * @package OCA\DAV\Connector\Sabre - */ -class DummyGetResponsePlugin extends \Sabre\DAV\ServerPlugin { - /** @var \Sabre\DAV\Server */ - protected $server; - - /** - * @param \Sabre\DAV\Server $server - * @return void - */ - function initialize(\Sabre\DAV\Server $server) { - $this->server = $server; - $this->server->on('method:GET', [$this, 'httpGet'], 200); - } - - /** - * @param RequestInterface $request - * @param ResponseInterface $response - * @return false - */ - function httpGet(RequestInterface $request, ResponseInterface $response) { - $string = 'This is the WebDAV interface. It can only be accessed by ' . - 'WebDAV clients such as the ownCloud desktop sync client.'; - $stream = fopen('php://memory','r+'); - fwrite($stream, $string); - rewind($stream); - - $response->setStatus(200); - $response->setBody($stream); - - return false; - } -} diff --git a/apps/dav/lib/connector/sabre/exception/entitytoolarge.php b/apps/dav/lib/connector/sabre/exception/entitytoolarge.php deleted file mode 100644 index d16e93bb637..00000000000 --- a/apps/dav/lib/connector/sabre/exception/entitytoolarge.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre\Exception; - -/** - * Entity Too Large - * - * This exception is thrown whenever a user tries to upload a file which exceeds hard limitations - * - */ -class EntityTooLarge extends \Sabre\DAV\Exception { - - /** - * Returns the HTTP status code for this exception - * - * @return int - */ - public function getHTTPCode() { - - return 413; - - } - -} diff --git a/apps/dav/lib/connector/sabre/exception/filelocked.php b/apps/dav/lib/connector/sabre/exception/filelocked.php deleted file mode 100644 index 03ced0e81e2..00000000000 --- a/apps/dav/lib/connector/sabre/exception/filelocked.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Owen Winkler <a_github@midnightcircus.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre\Exception; - -use Exception; - -class FileLocked extends \Sabre\DAV\Exception { - - public function __construct($message = "", $code = 0, Exception $previous = null) { - if($previous instanceof \OCP\Files\LockNotAcquiredException) { - $message = sprintf('Target file %s is locked by another process.', $previous->path); - } - parent::__construct($message, $code, $previous); - } - - /** - * Returns the HTTP status code for this exception - * - * @return int - */ - public function getHTTPCode() { - - return 423; - } -} diff --git a/apps/dav/lib/connector/sabre/exception/forbidden.php b/apps/dav/lib/connector/sabre/exception/forbidden.php deleted file mode 100644 index f2467e6b298..00000000000 --- a/apps/dav/lib/connector/sabre/exception/forbidden.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre\Exception; - -class Forbidden extends \Sabre\DAV\Exception\Forbidden { - - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - - /** - * @var bool - */ - private $retry; - - /** - * @param string $message - * @param bool $retry - * @param \Exception $previous - */ - public function __construct($message, $retry = false, \Exception $previous = null) { - parent::__construct($message, 0, $previous); - $this->retry = $retry; - } - - /** - * This method allows the exception to include additional information - * into the WebDAV error response - * - * @param \Sabre\DAV\Server $server - * @param \DOMElement $errorNode - * @return void - */ - public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) { - - // set ownCloud namespace - $errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD); - - // adding the retry node - $error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true)); - $errorNode->appendChild($error); - - // adding the message node - $error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage()); - $errorNode->appendChild($error); - } -} diff --git a/apps/dav/lib/connector/sabre/exception/invalidpath.php b/apps/dav/lib/connector/sabre/exception/invalidpath.php deleted file mode 100644 index 7951a0a89b7..00000000000 --- a/apps/dav/lib/connector/sabre/exception/invalidpath.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre\Exception; - -use Sabre\DAV\Exception; - -class InvalidPath extends Exception { - - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - - /** - * @var bool - */ - private $retry; - - /** - * @param string $message - * @param bool $retry - */ - public function __construct($message, $retry = false) { - parent::__construct($message); - $this->retry = $retry; - } - - /** - * Returns the HTTP status code for this exception - * - * @return int - */ - public function getHTTPCode() { - - return 400; - - } - - /** - * This method allows the exception to include additional information - * into the WebDAV error response - * - * @param \Sabre\DAV\Server $server - * @param \DOMElement $errorNode - * @return void - */ - public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) { - - // set ownCloud namespace - $errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD); - - // adding the retry node - $error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true)); - $errorNode->appendChild($error); - - // adding the message node - $error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage()); - $errorNode->appendChild($error); - } - -} diff --git a/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php b/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php deleted file mode 100644 index 99e3c222c75..00000000000 --- a/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre\Exception; - -/** - * Unsupported Media Type - * - * This exception is thrown whenever a user tries to upload a file which holds content which is not allowed - * - */ -class UnsupportedMediaType extends \Sabre\DAV\Exception { - - /** - * Returns the HTTP status code for this exception - * - * @return int - */ - public function getHTTPCode() { - - return 415; - - } - -} diff --git a/apps/dav/lib/connector/sabre/exceptionloggerplugin.php b/apps/dav/lib/connector/sabre/exceptionloggerplugin.php deleted file mode 100644 index 38bddef8769..00000000000 --- a/apps/dav/lib/connector/sabre/exceptionloggerplugin.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Pierre Jochem <pierrejochem@msn.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\ILogger; -use Sabre\DAV\Exception; -use Sabre\HTTP\Response; - -class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin { - protected $nonFatalExceptions = array( - 'Sabre\DAV\Exception\NotAuthenticated' => true, - // the sync client uses this to find out whether files exist, - // so it is not always an error, log it as debug - 'Sabre\DAV\Exception\NotFound' => true, - // this one mostly happens when the same file is uploaded at - // exactly the same time from two clients, only one client - // wins, the second one gets "Precondition failed" - 'Sabre\DAV\Exception\PreconditionFailed' => true, - // forbidden can be expected when trying to upload to - // read-only folders for example - 'Sabre\DAV\Exception\Forbidden' => true, - ); - - /** @var string */ - private $appName; - - /** @var ILogger */ - private $logger; - - /** - * @param string $loggerAppName app name to use when logging - * @param ILogger $logger - */ - public function __construct($loggerAppName, $logger) { - $this->appName = $loggerAppName; - $this->logger = $logger; - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - - $server->on('exception', array($this, 'logException'), 10); - } - - /** - * Log exception - * - */ - public function logException(\Exception $ex) { - $exceptionClass = get_class($ex); - $level = \OCP\Util::FATAL; - if (isset($this->nonFatalExceptions[$exceptionClass])) { - $level = \OCP\Util::DEBUG; - } - - $message = $ex->getMessage(); - if ($ex instanceof Exception) { - if (empty($message)) { - $response = new Response($ex->getHTTPCode()); - $message = $response->getStatusText(); - } - $message = "HTTP/1.1 {$ex->getHTTPCode()} $message"; - } - - $user = \OC_User::getUser(); - - $exception = [ - 'Message' => $message, - 'Exception' => $exceptionClass, - 'Code' => $ex->getCode(), - 'Trace' => $ex->getTraceAsString(), - 'File' => $ex->getFile(), - 'Line' => $ex->getLine(), - 'User' => $user, - ]; - $this->logger->log($level, 'Exception: ' . json_encode($exception), ['app' => $this->appName]); - } -} diff --git a/apps/dav/lib/connector/sabre/fakelockerplugin.php b/apps/dav/lib/connector/sabre/fakelockerplugin.php deleted file mode 100644 index 6db8740bc13..00000000000 --- a/apps/dav/lib/connector/sabre/fakelockerplugin.php +++ /dev/null @@ -1,156 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use Sabre\DAV\Locks\LockInfo; -use Sabre\DAV\ServerPlugin; -use Sabre\DAV\Xml\Property\LockDiscovery; -use Sabre\DAV\Xml\Property\SupportedLock; -use Sabre\HTTP\RequestInterface; -use Sabre\HTTP\ResponseInterface; -use Sabre\DAV\PropFind; -use Sabre\DAV\INode; - -/** - * Class FakeLockerPlugin is a plugin only used when connections come in from - * OS X via Finder. The fake locking plugin does emulate Class 2 WebDAV support - * (locking of files) which allows Finder to access the storage in write mode as - * well. - * - * No real locking is performed, instead the plugin just returns always positive - * responses. - * - * @see https://github.com/owncloud/core/issues/17732 - * @package OCA\DAV\Connector\Sabre - */ -class FakeLockerPlugin extends ServerPlugin { - /** @var \Sabre\DAV\Server */ - private $server; - - /** {@inheritDoc} */ - public function initialize(\Sabre\DAV\Server $server) { - $this->server = $server; - $this->server->on('method:LOCK', [$this, 'fakeLockProvider'], 1); - $this->server->on('method:UNLOCK', [$this, 'fakeUnlockProvider'], 1); - $server->on('propFind', [$this, 'propFind']); - $server->on('validateTokens', [$this, 'validateTokens']); - } - - /** - * Indicate that we support LOCK and UNLOCK - * - * @param string $path - * @return string[] - */ - public function getHTTPMethods($path) { - return [ - 'LOCK', - 'UNLOCK', - ]; - } - - /** - * Indicate that we support locking - * - * @return integer[] - */ - function getFeatures() { - return [2]; - } - - /** - * Return some dummy response for PROPFIND requests with regard to locking - * - * @param PropFind $propFind - * @param INode $node - * @return void - */ - function propFind(PropFind $propFind, INode $node) { - $propFind->handle('{DAV:}supportedlock', function() { - return new SupportedLock(true); - }); - $propFind->handle('{DAV:}lockdiscovery', function() use ($propFind) { - return new LockDiscovery([]); - }); - } - - /** - * Mark a locking token always as valid - * - * @param RequestInterface $request - * @param array $conditions - */ - public function validateTokens(RequestInterface $request, &$conditions) { - foreach($conditions as &$fileCondition) { - if(isset($fileCondition['tokens'])) { - foreach($fileCondition['tokens'] as &$token) { - if(isset($token['token'])) { - if(substr($token['token'], 0, 16) === 'opaquelocktoken:') { - $token['validToken'] = true; - } - } - } - } - } - } - - /** - * Fakes a successful LOCK - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - public function fakeLockProvider(RequestInterface $request, - ResponseInterface $response) { - - $lockInfo = new LockInfo(); - $lockInfo->token = md5($request->getPath()); - $lockInfo->uri = $request->getPath(); - $lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY; - $lockInfo->timeout = 1800; - - $body = $this->server->xml->write('{DAV:}prop', [ - '{DAV:}lockdiscovery' => - new LockDiscovery([$lockInfo]) - ]); - - $response->setBody($body); - - return false; - } - - /** - * Fakes a successful LOCK - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - public function fakeUnlockProvider(RequestInterface $request, - ResponseInterface $response) { - $response->setStatus(204); - $response->setHeader('Content-Length', '0'); - return false; - } -} diff --git a/apps/dav/lib/connector/sabre/file.php b/apps/dav/lib/connector/sabre/file.php deleted file mode 100644 index 943e9150e74..00000000000 --- a/apps/dav/lib/connector/sabre/file.php +++ /dev/null @@ -1,567 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Jakob Sack <mail@jakobsack.de> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Owen Winkler <a_github@midnightcircus.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OC\Files\Filesystem; -use OCA\DAV\Connector\Sabre\Exception\EntityTooLarge; -use OCA\DAV\Connector\Sabre\Exception\FileLocked; -use OCA\DAV\Connector\Sabre\Exception\Forbidden as DAVForbiddenException; -use OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType; -use OCP\Encryption\Exceptions\GenericEncryptionException; -use OCP\Files\EntityTooLargeException; -use OCP\Files\ForbiddenException; -use OCP\Files\InvalidContentException; -use OCP\Files\InvalidPathException; -use OCP\Files\LockNotAcquiredException; -use OCP\Files\NotPermittedException; -use OCP\Files\StorageNotAvailableException; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; -use Sabre\DAV\Exception; -use Sabre\DAV\Exception\BadRequest; -use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\NotImplemented; -use Sabre\DAV\Exception\ServiceUnavailable; -use Sabre\DAV\IFile; - -class File extends Node implements IFile { - - /** - * Updates the data - * - * The data argument is a readable stream resource. - * - * After a successful put operation, you may choose to return an ETag. The - * etag must always be surrounded by double-quotes. These quotes must - * appear in the actual string you're returning. - * - * Clients may use the ETag from a PUT request to later on make sure that - * when they update the file, the contents haven't changed in the mean - * time. - * - * If you don't plan to store the file byte-by-byte, and you return a - * different object on a subsequent GET you are strongly recommended to not - * return an ETag, and just return null. - * - * @param resource $data - * - * @throws Forbidden - * @throws UnsupportedMediaType - * @throws BadRequest - * @throws Exception - * @throws EntityTooLarge - * @throws ServiceUnavailable - * @throws FileLocked - * @return string|null - */ - public function put($data) { - try { - $exists = $this->fileView->file_exists($this->path); - if ($this->info && $exists && !$this->info->isUpdateable()) { - throw new Forbidden(); - } - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("File is not updatable: " . $e->getMessage()); - } - - // verify path of the target - $this->verifyPath(); - - // chunked handling - if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - try { - return $this->createFileChunked($data); - } catch (\Exception $e) { - $this->convertToSabreException($e); - } - } - - list($partStorage) = $this->fileView->resolvePath($this->path); - $needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1); - - if ($needsPartFile) { - // mark file as partial while uploading (ignored by the scanner) - $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part'; - } else { - // upload file directly as the final path - $partFilePath = $this->path; - } - - // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share) - /** @var \OC\Files\Storage\Storage $partStorage */ - list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath); - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = $this->fileView->resolvePath($this->path); - try { - $target = $partStorage->fopen($internalPartPath, 'wb'); - if ($target === false) { - \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR); - // because we have no clue about the cause we can only throw back a 500/Internal Server Error - throw new Exception('Could not write file contents'); - } - list($count, $result) = \OC_Helper::streamCopy($data, $target); - fclose($target); - - if ($result === false) { - $expected = -1; - if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = $_SERVER['CONTENT_LENGTH']; - } - throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )'); - } - - // if content length is sent by client: - // double check if the file was fully received - // compare expected and actual size - if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { - $expected = $_SERVER['CONTENT_LENGTH']; - if ($count != $expected) { - throw new BadRequest('expected filesize ' . $expected . ' got ' . $count); - } - } - - } catch (\Exception $e) { - if ($needsPartFile) { - $partStorage->unlink($internalPartPath); - } - $this->convertToSabreException($e); - } - - try { - $view = \OC\Files\Filesystem::getView(); - if ($view) { - $run = $this->emitPreHooks($exists); - } else { - $run = true; - } - - try { - $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE); - } catch (LockedException $e) { - if ($needsPartFile) { - $partStorage->unlink($internalPartPath); - } - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - if ($needsPartFile) { - // rename to correct path - try { - if ($run) { - $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath); - $fileExists = $storage->file_exists($internalPath); - } - if (!$run || $renameOkay === false || $fileExists === false) { - \OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR); - throw new Exception('Could not rename part file to final file'); - } - } catch (ForbiddenException $ex) { - throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry()); - } catch (\Exception $e) { - $partStorage->unlink($internalPartPath); - $this->convertToSabreException($e); - } - } - - // since we skipped the view we need to scan and emit the hooks ourselves - $storage->getUpdater()->update($internalPath); - - try { - $this->changeLock(ILockingProvider::LOCK_SHARED); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - if ($view) { - $this->emitPostHooks($exists); - } - - // allow sync clients to send the mtime along in a header - $request = \OC::$server->getRequest(); - if (isset($request->server['HTTP_X_OC_MTIME'])) { - if ($this->fileView->touch($this->path, $request->server['HTTP_X_OC_MTIME'])) { - header('X-OC-MTime: accepted'); - } - } - - $this->refreshInfo(); - - if (isset($request->server['HTTP_OC_CHECKSUM'])) { - $checksum = trim($request->server['HTTP_OC_CHECKSUM']); - $this->fileView->putFileInfo($this->path, ['checksum' => $checksum]); - $this->refreshInfo(); - } else if ($this->getChecksum() !== null && $this->getChecksum() !== '') { - $this->fileView->putFileInfo($this->path, ['checksum' => '']); - $this->refreshInfo(); - } - - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage()); - } - - return '"' . $this->info->getEtag() . '"'; - } - - private function getPartFileBasePath($path) { - $partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true); - if ($partFileInStorage) { - return $path; - } else { - return md5($path); // will place it in the root of the view with a unique name - } - } - - /** - * @param string $path - */ - private function emitPreHooks($exists, $path = null) { - if (is_null($path)) { - $path = $this->path; - } - $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path)); - $run = true; - - if (!$exists) { - \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array( - \OC\Files\Filesystem::signal_param_path => $hookPath, - \OC\Files\Filesystem::signal_param_run => &$run, - )); - } else { - \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array( - \OC\Files\Filesystem::signal_param_path => $hookPath, - \OC\Files\Filesystem::signal_param_run => &$run, - )); - } - \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array( - \OC\Files\Filesystem::signal_param_path => $hookPath, - \OC\Files\Filesystem::signal_param_run => &$run, - )); - return $run; - } - - /** - * @param string $path - */ - private function emitPostHooks($exists, $path = null) { - if (is_null($path)) { - $path = $this->path; - } - $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path)); - if (!$exists) { - \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array( - \OC\Files\Filesystem::signal_param_path => $hookPath - )); - } else { - \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array( - \OC\Files\Filesystem::signal_param_path => $hookPath - )); - } - \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array( - \OC\Files\Filesystem::signal_param_path => $hookPath - )); - } - - /** - * Returns the data - * - * @return resource - * @throws Forbidden - * @throws ServiceUnavailable - */ - public function get() { - //throw exception if encryption is disabled but files are still encrypted - try { - $res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb'); - if ($res === false) { - throw new ServiceUnavailable("Could not open file"); - } - return $res; - } catch (GenericEncryptionException $e) { - // returning 503 will allow retry of the operation at a later point in time - throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage()); - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("Failed to open file: " . $e->getMessage()); - } catch (ForbiddenException $ex) { - throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Delete the current file - * - * @throws Forbidden - * @throws ServiceUnavailable - */ - public function delete() { - if (!$this->info->isDeletable()) { - throw new Forbidden(); - } - - try { - if (!$this->fileView->unlink($this->path)) { - // assume it wasn't possible to delete due to permissions - throw new Forbidden(); - } - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage()); - } catch (ForbiddenException $ex) { - throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Returns the mime-type for a file - * - * If null is returned, we'll assume application/octet-stream - * - * @return string - */ - public function getContentType() { - $mimeType = $this->info->getMimetype(); - - // PROPFIND needs to return the correct mime type, for consistency with the web UI - if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') { - return $mimeType; - } - return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType); - } - - /** - * @return array|false - */ - public function getDirectDownload() { - if (\OCP\App::isEnabled('encryption')) { - return []; - } - /** @var \OCP\Files\Storage $storage */ - list($storage, $internalPath) = $this->fileView->resolvePath($this->path); - if (is_null($storage)) { - return []; - } - - return $storage->getDirectDownload($internalPath); - } - - /** - * @param resource $data - * @return null|string - * @throws Exception - * @throws BadRequest - * @throws NotImplemented - * @throws ServiceUnavailable - */ - private function createFileChunked($data) { - list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path); - - $info = \OC_FileChunking::decodeName($name); - if (empty($info)) { - throw new NotImplemented('Invalid chunk name'); - } - - $chunk_handler = new \OC_FileChunking($info); - $bytesWritten = $chunk_handler->store($info['index'], $data); - - //detect aborted upload - if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { - if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = $_SERVER['CONTENT_LENGTH']; - if ($bytesWritten != $expected) { - $chunk_handler->remove($info['index']); - throw new BadRequest( - 'expected filesize ' . $expected . ' got ' . $bytesWritten); - } - } - } - - if ($chunk_handler->isComplete()) { - list($storage,) = $this->fileView->resolvePath($path); - $needsPartFile = $this->needsPartFile($storage); - $partFile = null; - - $targetPath = $path . '/' . $info['name']; - /** @var \OC\Files\Storage\Storage $targetStorage */ - list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath); - - $exists = $this->fileView->file_exists($targetPath); - - try { - $this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED); - - $this->emitPreHooks($exists, $targetPath); - $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE); - /** @var \OC\Files\Storage\Storage $targetStorage */ - list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath); - - if ($needsPartFile) { - // we first assembly the target file as a part file - $partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part'; - /** @var \OC\Files\Storage\Storage $targetStorage */ - list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile); - - - $chunk_handler->file_assemble($partStorage, $partInternalPath); - - // here is the final atomic rename - $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath); - $fileExists = $targetStorage->file_exists($targetInternalPath); - if ($renameOkay === false || $fileExists === false) { - \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::rename() failed', \OCP\Util::ERROR); - // only delete if an error occurred and the target file was already created - if ($fileExists) { - // set to null to avoid double-deletion when handling exception - // stray part file - $partFile = null; - $targetStorage->unlink($targetInternalPath); - } - $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED); - throw new Exception('Could not rename part file assembled from chunks'); - } - } else { - // assemble directly into the final file - $chunk_handler->file_assemble($targetStorage, $targetInternalPath); - } - - // allow sync clients to send the mtime along in a header - $request = \OC::$server->getRequest(); - if (isset($request->server['HTTP_X_OC_MTIME'])) { - if ($targetStorage->touch($targetInternalPath, $request->server['HTTP_X_OC_MTIME'])) { - header('X-OC-MTime: accepted'); - } - } - - // since we skipped the view we need to scan and emit the hooks ourselves - $targetStorage->getUpdater()->update($targetInternalPath); - - $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED); - - $this->emitPostHooks($exists, $targetPath); - - // FIXME: should call refreshInfo but can't because $this->path is not the of the final file - $info = $this->fileView->getFileInfo($targetPath); - - if (isset($request->server['HTTP_OC_CHECKSUM'])) { - $checksum = trim($request->server['HTTP_OC_CHECKSUM']); - $this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]); - } else if ($info->getChecksum() !== null && $info->getChecksum() !== '') { - $this->fileView->putFileInfo($this->path, ['checksum' => '']); - } - - $this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED); - - return $info->getEtag(); - } catch (\Exception $e) { - if ($partFile !== null) { - $targetStorage->unlink($targetInternalPath); - } - $this->convertToSabreException($e); - } - } - - return null; - } - - /** - * Returns whether a part file is needed for the given storage - * or whether the file can be assembled/uploaded directly on the - * target storage. - * - * @param \OCP\Files\Storage $storage - * @return bool true if the storage needs part file handling - */ - private function needsPartFile($storage) { - // TODO: in the future use ChunkHandler provided by storage - // and/or add method on Storage called "needsPartFile()" - return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') && - !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud'); - } - - /** - * Convert the given exception to a SabreException instance - * - * @param \Exception $e - * - * @throws \Sabre\DAV\Exception - */ - private function convertToSabreException(\Exception $e) { - if ($e instanceof \Sabre\DAV\Exception) { - throw $e; - } - if ($e instanceof NotPermittedException) { - // a more general case - due to whatever reason the content could not be written - throw new Forbidden($e->getMessage(), 0, $e); - } - if ($e instanceof ForbiddenException) { - // the path for the file was forbidden - throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e); - } - if ($e instanceof EntityTooLargeException) { - // the file is too big to be stored - throw new EntityTooLarge($e->getMessage(), 0, $e); - } - if ($e instanceof InvalidContentException) { - // the file content is not permitted - throw new UnsupportedMediaType($e->getMessage(), 0, $e); - } - if ($e instanceof InvalidPathException) { - // the path for the file was not valid - // TODO: find proper http status code for this case - throw new Forbidden($e->getMessage(), 0, $e); - } - if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) { - // the file is currently being written to by another process - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - if ($e instanceof GenericEncryptionException) { - // returning 503 will allow retry of the operation at a later point in time - throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e); - } - if ($e instanceof StorageNotAvailableException) { - throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e); - } - - throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e); - } - - /** - * Get the checksum for this file - * - * @return string - */ - public function getChecksum() { - return $this->info->getChecksum(); - } -} diff --git a/apps/dav/lib/connector/sabre/filesplugin.php b/apps/dav/lib/connector/sabre/filesplugin.php deleted file mode 100644 index 8822deb1661..00000000000 --- a/apps/dav/lib/connector/sabre/filesplugin.php +++ /dev/null @@ -1,398 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OC\Files\View; -use OCA\DAV\Upload\FutureFile; -use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\IFile; -use \Sabre\DAV\PropFind; -use \Sabre\DAV\PropPatch; -use Sabre\DAV\ServerPlugin; -use Sabre\DAV\Tree; -use \Sabre\HTTP\RequestInterface; -use \Sabre\HTTP\ResponseInterface; -use OCP\Files\StorageNotAvailableException; -use OCP\IConfig; - -class FilesPlugin extends ServerPlugin { - - // namespace - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id'; - const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid'; - const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions'; - const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions'; - const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL'; - const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size'; - const GETETAG_PROPERTYNAME = '{DAV:}getetag'; - const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; - const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id'; - const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name'; - const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums'; - const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint'; - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var Tree - */ - private $tree; - - /** - * Whether this is public webdav. - * If true, some returned information will be stripped off. - * - * @var bool - */ - private $isPublic; - - /** - * @var View - */ - private $fileView; - - /** - * @var bool - */ - private $downloadAttachment; - - /** - * @var IConfig - */ - private $config; - - /** - * @param Tree $tree - * @param View $view - * @param bool $isPublic - * @param bool $downloadAttachment - */ - public function __construct(Tree $tree, - View $view, - IConfig $config, - $isPublic = false, - $downloadAttachment = true) { - $this->tree = $tree; - $this->fileView = $view; - $this->config = $config; - $this->isPublic = $isPublic; - $this->downloadAttachment = $downloadAttachment; - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - - $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; - $server->protectedProperties[] = self::FILEID_PROPERTYNAME; - $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME; - $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME; - $server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME; - $server->protectedProperties[] = self::SIZE_PROPERTYNAME; - $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME; - $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME; - $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME; - $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME; - $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME; - - // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH - $allowedProperties = ['{DAV:}getetag']; - $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties); - - $this->server = $server; - $this->server->on('propFind', array($this, 'handleGetProperties')); - $this->server->on('propPatch', array($this, 'handleUpdateProperties')); - $this->server->on('afterBind', array($this, 'sendFileIdHeader')); - $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader')); - $this->server->on('afterMethod:GET', [$this,'httpGet']); - $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken')); - $this->server->on('afterResponse', function($request, ResponseInterface $response) { - $body = $response->getBody(); - if (is_resource($body)) { - fclose($body); - } - }); - $this->server->on('beforeMove', [$this, 'checkMove']); - } - - /** - * Plugin that checks if a move can actually be performed. - * - * @param string $source source path - * @param string $destination destination path - * @throws Forbidden - * @throws NotFound - */ - function checkMove($source, $destination) { - $sourceNode = $this->tree->getNodeForPath($source); - if ($sourceNode instanceof FutureFile) { - return; - } - list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source); - list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination); - - if ($sourceDir !== $destinationDir) { - $sourceFileInfo = $this->fileView->getFileInfo($source); - - if ($sourceFileInfo === false) { - throw new NotFound($source . ' does not exist'); - } - - if (!$sourceFileInfo->isDeletable()) { - throw new Forbidden($source . " cannot be deleted"); - } - } - } - - /** - * This sets a cookie to be able to recognize the start of the download - * the content must not be longer than 32 characters and must only contain - * alphanumeric characters - * - * @param RequestInterface $request - * @param ResponseInterface $response - */ - function handleDownloadToken(RequestInterface $request, ResponseInterface $response) { - $queryParams = $request->getQueryParameters(); - - /** - * this sets a cookie to be able to recognize the start of the download - * the content must not be longer than 32 characters and must only contain - * alphanumeric characters - */ - if (isset($queryParams['downloadStartSecret'])) { - $token = $queryParams['downloadStartSecret']; - if (!isset($token[32]) - && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) { - // FIXME: use $response->setHeader() instead - setcookie('ocDownloadStarted', $token, time() + 20, '/'); - } - } - } - - /** - * Add headers to file download - * - * @param RequestInterface $request - * @param ResponseInterface $response - */ - function httpGet(RequestInterface $request, ResponseInterface $response) { - // Only handle valid files - $node = $this->tree->getNodeForPath($request->getPath()); - if (!($node instanceof IFile)) return; - - // adds a 'Content-Disposition: attachment' header - if ($this->downloadAttachment) { - $response->addHeader('Content-Disposition', 'attachment'); - } - - if ($node instanceof \OCA\DAV\Connector\Sabre\File) { - //Add OC-Checksum header - /** @var $node File */ - $checksum = $node->getChecksum(); - if ($checksum !== null && $checksum !== '') { - $response->addHeader('OC-Checksum', $checksum); - } - } - } - - /** - * Adds all ownCloud-specific properties - * - * @param PropFind $propFind - * @param \Sabre\DAV\INode $node - * @return void - */ - public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) { - - $httpRequest = $this->server->httpRequest; - - if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { - - $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) { - return $node->getFileId(); - }); - - $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) { - return $node->getInternalFileId(); - }); - - $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) { - $perms = $node->getDavPermissions(); - if ($this->isPublic) { - // remove mount information - $perms = str_replace(['S', 'M'], '', $perms); - } - return $perms; - }); - - $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) { - return $node->getSharePermissions( - $httpRequest->getRawServerValue('PHP_AUTH_USER') - ); - }); - - $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) { - return $node->getETag(); - }); - - $propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) { - $owner = $node->getOwner(); - return $owner->getUID(); - }); - $propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) { - $owner = $node->getOwner(); - $displayName = $owner->getDisplayName(); - return $displayName; - }); - - $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) { - if ($node->getPath() === '/') { - return $this->config->getSystemValue('data-fingerprint', ''); - } - }); - } - - if ($node instanceof \OCA\DAV\Files\FilesHome) { - $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) { - return $this->config->getSystemValue('data-fingerprint', ''); - }); - } - - if ($node instanceof \OCA\DAV\Connector\Sabre\File) { - $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) { - /** @var $node \OCA\DAV\Connector\Sabre\File */ - try { - $directDownloadUrl = $node->getDirectDownload(); - if (isset($directDownloadUrl['url'])) { - return $directDownloadUrl['url']; - } - } catch (StorageNotAvailableException $e) { - return false; - } - return false; - }); - - $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) { - $checksum = $node->getChecksum(); - if ($checksum === NULL || $checksum === '') { - return null; - } - - return new ChecksumList($checksum); - }); - - } - - if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) { - $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) { - return $node->getSize(); - }); - } - } - - /** - * Update ownCloud-specific properties - * - * @param string $path - * @param PropPatch $propPatch - * - * @return void - */ - public function handleUpdateProperties($path, PropPatch $propPatch) { - $propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($path) { - if (empty($time)) { - return false; - } - $node = $this->tree->getNodeForPath($path); - if (is_null($node)) { - return 404; - } - $node->touch($time); - return true; - }); - $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) { - if (empty($etag)) { - return false; - } - $node = $this->tree->getNodeForPath($path); - if (is_null($node)) { - return 404; - } - if ($node->setEtag($etag) !== -1) { - return true; - } - return false; - }); - } - - /** - * @param string $filePath - * @param \Sabre\DAV\INode $node - * @throws \Sabre\DAV\Exception\BadRequest - */ - public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) { - // chunked upload handling - if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath); - $info = \OC_FileChunking::decodeName($name); - if (!empty($info)) { - $filePath = $path . '/' . $info['name']; - } - } - - // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder - if (!$this->server->tree->nodeExists($filePath)) { - return; - } - $node = $this->server->tree->getNodeForPath($filePath); - if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { - $fileId = $node->getFileId(); - if (!is_null($fileId)) { - $this->server->httpResponse->setHeader('OC-FileId', $fileId); - } - } - } - -} diff --git a/apps/dav/lib/connector/sabre/filesreportplugin.php b/apps/dav/lib/connector/sabre/filesreportplugin.php deleted file mode 100644 index d4e1cbe3b20..00000000000 --- a/apps/dav/lib/connector/sabre/filesreportplugin.php +++ /dev/null @@ -1,333 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OC\Files\View; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\PreconditionFailed; -use Sabre\DAV\Exception\ReportNotSupported; -use Sabre\DAV\Exception\BadRequest; -use Sabre\DAV\ServerPlugin; -use Sabre\DAV\Tree; -use Sabre\DAV\Xml\Element\Response; -use Sabre\DAV\Xml\Response\MultiStatus; -use Sabre\DAV\PropFind; -use OCP\SystemTag\ISystemTagObjectMapper; -use OCP\IUserSession; -use OCP\Files\Folder; -use OCP\IGroupManager; -use OCP\SystemTag\ISystemTagManager; -use OCP\SystemTag\TagNotFoundException; - -class FilesReportPlugin extends ServerPlugin { - - // namespace - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - const REPORT_NAME = '{http://owncloud.org/ns}filter-files'; - const SYSTEMTAG_PROPERTYNAME = '{http://owncloud.org/ns}systemtag'; - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var Tree - */ - private $tree; - - /** - * @var View - */ - private $fileView; - - /** - * @var ISystemTagManager - */ - private $tagManager; - - /** - * @var ISystemTagObjectMapper - */ - private $tagMapper; - - /** - * @var IUserSession - */ - private $userSession; - - /** - * @var IGroupManager - */ - private $groupManager; - - /** - * @var Folder - */ - private $userFolder; - - /** - * @param Tree $tree - * @param View $view - */ - public function __construct(Tree $tree, - View $view, - ISystemTagManager $tagManager, - ISystemTagObjectMapper $tagMapper, - IUserSession $userSession, - IGroupManager $groupManager, - Folder $userFolder - ) { - $this->tree = $tree; - $this->fileView = $view; - $this->tagManager = $tagManager; - $this->tagMapper = $tagMapper; - $this->userSession = $userSession; - $this->groupManager = $groupManager; - $this->userFolder = $userFolder; - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - - $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; - - $this->server = $server; - $this->server->on('report', array($this, 'onReport')); - } - - /** - * Returns a list of reports this plugin supports. - * - * This will be used in the {DAV:}supported-report-set property. - * - * @param string $uri - * @return array - */ - public function getSupportedReportSet($uri) { - return [self::REPORT_NAME]; - } - - /** - * REPORT operations to look for files - * - * @param string $reportName - * @param [] $report - * @param string $uri - * @return bool - * @throws NotFound - * @throws ReportNotSupported - */ - public function onReport($reportName, $report, $uri) { - $reportTargetNode = $this->server->tree->getNodeForPath($uri); - if (!$reportTargetNode instanceof Directory || $reportName !== self::REPORT_NAME) { - throw new ReportNotSupported(); - } - - $ns = '{' . $this::NS_OWNCLOUD . '}'; - $requestedProps = []; - $filterRules = []; - - // parse report properties and gather filter info - foreach ($report as $reportProps) { - $name = $reportProps['name']; - if ($name === $ns . 'filter-rules') { - $filterRules = $reportProps['value']; - } else if ($name === '{DAV:}prop') { - // propfind properties - foreach ($reportProps['value'] as $propVal) { - $requestedProps[] = $propVal['name']; - } - } - } - - if (empty($filterRules)) { - // an empty filter would return all existing files which would be slow - throw new BadRequest('Missing filter-rule block in request'); - } - - // gather all file ids matching filter - try { - $resultFileIds = $this->processFilterRules($filterRules); - } catch (TagNotFoundException $e) { - throw new PreconditionFailed('Cannot filter by non-existing tag', 0, $e); - } - - // find sabre nodes by file id, restricted to the root node path - $results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds); - - $responses = $this->prepareResponses($requestedProps, $results); - - $xml = $this->server->xml->write( - '{DAV:}multistatus', - new MultiStatus($responses) - ); - - $this->server->httpResponse->setStatus(207); - $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8'); - $this->server->httpResponse->setBody($xml); - - return false; - } - - /** - * Find file ids matching the given filter rules - * - * @param array $filterRules - * @return array array of unique file id results - * - * @throws TagNotFoundException whenever a tag was not found - */ - protected function processFilterRules($filterRules) { - $ns = '{' . $this::NS_OWNCLOUD . '}'; - $resultFileIds = null; - $systemTagIds = []; - foreach ($filterRules as $filterRule) { - if ($filterRule['name'] === $ns . 'systemtag') { - $systemTagIds[] = $filterRule['value']; - } - } - - // check user permissions, if applicable - if (!$this->isAdmin()) { - // check visibility/permission - $tags = $this->tagManager->getTagsByIds($systemTagIds); - $unknownTagIds = []; - foreach ($tags as $tag) { - if (!$tag->isUserVisible()) { - $unknownTagIds[] = $tag->getId(); - } - } - - if (!empty($unknownTagIds)) { - throw new TagNotFoundException('Tag with ids ' . implode(', ', $unknownTagIds) . ' not found'); - } - } - - // fetch all file ids and intersect them - foreach ($systemTagIds as $systemTagId) { - $fileIds = $this->tagMapper->getObjectIdsForTags($systemTagId, 'files'); - - if (empty($fileIds)) { - // This tag has no files, nothing can ever show up - return []; - } - - // first run ? - if ($resultFileIds === null) { - $resultFileIds = $fileIds; - } else { - $resultFileIds = array_intersect($resultFileIds, $fileIds); - } - - if (empty($resultFileIds)) { - // Empty intersection, nothing can show up anymore - return []; - } - } - return $resultFileIds; - } - - /** - * Prepare propfind response for the given nodes - * - * @param string[] $requestedProps requested properties - * @param Node[] nodes nodes for which to fetch and prepare responses - * @return Response[] - */ - public function prepareResponses($requestedProps, $nodes) { - $responses = []; - foreach ($nodes as $node) { - $propFind = new PropFind($node->getPath(), $requestedProps); - - $this->server->getPropertiesByNode($propFind, $node); - // copied from Sabre Server's getPropertiesForPath - $result = $propFind->getResultForMultiStatus(); - $result['href'] = $propFind->getPath(); - - $resourceType = $this->server->getResourceTypeForNode($node); - if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) { - $result['href'] .= '/'; - } - - $responses[] = new Response( - rtrim($this->server->getBaseUri(), '/') . $node->getPath(), - $result, - 200 - ); - } - return $responses; - } - - /** - * Find Sabre nodes by file ids - * - * @param Node $rootNode root node for search - * @param array $fileIds file ids - * @return Node[] array of Sabre nodes - */ - public function findNodesByFileIds($rootNode, $fileIds) { - $folder = $this->userFolder; - if (trim($rootNode->getPath(), '/') !== '') { - $folder = $folder->get($rootNode->getPath()); - } - - $results = []; - foreach ($fileIds as $fileId) { - $entry = $folder->getById($fileId); - if ($entry) { - $entry = current($entry); - if ($entry instanceof \OCP\Files\File) { - $results[] = new File($this->fileView, $entry); - } else if ($entry instanceof \OCP\Files\Folder) { - $results[] = new Directory($this->fileView, $entry); - } - } - } - - return $results; - } - - /** - * Returns whether the currently logged in user is an administrator - */ - private function isAdmin() { - $user = $this->userSession->getUser(); - if ($user !== null) { - return $this->groupManager->isAdmin($user->getUID()); - } - return false; - } -} diff --git a/apps/dav/lib/connector/sabre/lockplugin.php b/apps/dav/lib/connector/sabre/lockplugin.php deleted file mode 100644 index 66da39a57c8..00000000000 --- a/apps/dav/lib/connector/sabre/lockplugin.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCA\DAV\Connector\Sabre\Exception\FileLocked; -use OCA\DAV\Connector\Sabre\Node; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\ServerPlugin; -use Sabre\HTTP\RequestInterface; - -class LockPlugin extends ServerPlugin { - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * {@inheritdoc} - */ - public function initialize(\Sabre\DAV\Server $server) { - $this->server = $server; - $this->server->on('beforeMethod', [$this, 'getLock'], 50); - $this->server->on('afterMethod', [$this, 'releaseLock'], 50); - } - - public function getLock(RequestInterface $request) { - // we can't listen on 'beforeMethod:PUT' due to order of operations with setting up the tree - // so instead we limit ourselves to the PUT method manually - if ($request->getMethod() !== 'PUT' || isset($_SERVER['HTTP_OC_CHUNKED'])) { - return; - } - try { - $node = $this->server->tree->getNodeForPath($request->getPath()); - } catch (NotFound $e) { - return; - } - if ($node instanceof Node) { - try { - $node->acquireLock(ILockingProvider::LOCK_SHARED); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - } - } - - public function releaseLock(RequestInterface $request) { - if ($request->getMethod() !== 'PUT' || isset($_SERVER['HTTP_OC_CHUNKED'])) { - return; - } - try { - $node = $this->server->tree->getNodeForPath($request->getPath()); - } catch (NotFound $e) { - return; - } - if ($node instanceof Node) { - $node->releaseLock(ILockingProvider::LOCK_SHARED); - } - } -} diff --git a/apps/dav/lib/connector/sabre/maintenanceplugin.php b/apps/dav/lib/connector/sabre/maintenanceplugin.php deleted file mode 100644 index 6e9a5930b78..00000000000 --- a/apps/dav/lib/connector/sabre/maintenanceplugin.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\IConfig; -use Sabre\DAV\Exception\ServiceUnavailable; -use Sabre\DAV\ServerPlugin; - -class MaintenancePlugin extends ServerPlugin { - - /** @var IConfig */ - private $config; - - /** - * Reference to main server object - * - * @var Server - */ - private $server; - - /** - * @param IConfig $config - */ - public function __construct(IConfig $config = null) { - $this->config = $config; - if (is_null($config)) { - $this->config = \OC::$server->getConfig(); - } - } - - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - $this->server = $server; - $this->server->on('beforeMethod', array($this, 'checkMaintenanceMode'), 1); - } - - /** - * This method is called before any HTTP method and returns http status code 503 - * in case the system is in maintenance mode. - * - * @throws ServiceUnavailable - * @return bool - */ - public function checkMaintenanceMode() { - if ($this->config->getSystemValue('singleuser', false)) { - throw new ServiceUnavailable('System in single user mode.'); - } - if ($this->config->getSystemValue('maintenance', false)) { - throw new ServiceUnavailable('System in maintenance mode.'); - } - if (\OC::checkUpgrade(false)) { - throw new ServiceUnavailable('Upgrade needed'); - } - - return true; - } -} diff --git a/apps/dav/lib/connector/sabre/node.php b/apps/dav/lib/connector/sabre/node.php deleted file mode 100644 index ccc035063cd..00000000000 --- a/apps/dav/lib/connector/sabre/node.php +++ /dev/null @@ -1,348 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Jakob Sack <mail@jakobsack.de> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Klaas Freitag <freitag@owncloud.com> - * @author Markus Goetz <markus@woboq.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OC\Files\Mount\MoveableMount; -use OCA\DAV\Connector\Sabre\Exception\InvalidPath; -use OCP\Share\Exceptions\ShareNotFound; -use OCP\Share\IManager; - - -abstract class Node implements \Sabre\DAV\INode { - - /** - * @var \OC\Files\View - */ - protected $fileView; - - /** - * The path to the current node - * - * @var string - */ - protected $path; - - /** - * node properties cache - * - * @var array - */ - protected $property_cache = null; - - /** - * @var \OCP\Files\FileInfo - */ - protected $info; - - /** - * @var IManager - */ - protected $shareManager; - - /** - * Sets up the node, expects a full path name - * - * @param \OC\Files\View $view - * @param \OCP\Files\FileInfo $info - * @param IManager $shareManager - */ - public function __construct($view, $info, IManager $shareManager = null) { - $this->fileView = $view; - $this->path = $this->fileView->getRelativePath($info->getPath()); - $this->info = $info; - if ($shareManager) { - $this->shareManager = $shareManager; - } else { - $this->shareManager = \OC::$server->getShareManager(); - } - } - - protected function refreshInfo() { - $this->info = $this->fileView->getFileInfo($this->path); - } - - /** - * Returns the name of the node - * - * @return string - */ - public function getName() { - return $this->info->getName(); - } - - /** - * Returns the full path - * - * @return string - */ - public function getPath() { - return $this->path; - } - - /** - * Renames the node - * - * @param string $name The new name - * @throws \Sabre\DAV\Exception\BadRequest - * @throws \Sabre\DAV\Exception\Forbidden - */ - public function setName($name) { - - // rename is only allowed if the update privilege is granted - if (!$this->info->isUpdateable()) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - - list($parentPath,) = \Sabre\HTTP\URLUtil::splitPath($this->path); - list(, $newName) = \Sabre\HTTP\URLUtil::splitPath($name); - - // verify path of the target - $this->verifyPath(); - - $newPath = $parentPath . '/' . $newName; - - $this->fileView->rename($this->path, $newPath); - - $this->path = $newPath; - - $this->refreshInfo(); - } - - public function setPropertyCache($property_cache) { - $this->property_cache = $property_cache; - } - - /** - * Returns the last modification time, as a unix timestamp - * - * @return int timestamp as integer - */ - public function getLastModified() { - $timestamp = $this->info->getMtime(); - if (!empty($timestamp)) { - return (int)$timestamp; - } - return $timestamp; - } - - /** - * sets the last modification time of the file (mtime) to the value given - * in the second parameter or to now if the second param is empty. - * Even if the modification time is set to a custom value the access time is set to now. - */ - public function touch($mtime) { - $this->fileView->touch($this->path, $mtime); - $this->refreshInfo(); - } - - /** - * Returns the ETag for a file - * - * An ETag is a unique identifier representing the current version of the - * file. If the file changes, the ETag MUST change. The ETag is an - * arbitrary string, but MUST be surrounded by double-quotes. - * - * Return null if the ETag can not effectively be determined - * - * @return string - */ - public function getETag() { - return '"' . $this->info->getEtag() . '"'; - } - - /** - * Sets the ETag - * - * @param string $etag - * - * @return int file id of updated file or -1 on failure - */ - public function setETag($etag) { - return $this->fileView->putFileInfo($this->path, array('etag' => $etag)); - } - - /** - * Returns the size of the node, in bytes - * - * @return integer - */ - public function getSize() { - return $this->info->getSize(); - } - - /** - * Returns the cache's file id - * - * @return int - */ - public function getId() { - return $this->info->getId(); - } - - /** - * @return string|null - */ - public function getFileId() { - if ($this->info->getId()) { - $instanceId = \OC_Util::getInstanceId(); - $id = sprintf('%08d', $this->info->getId()); - return $id . $instanceId; - } - - return null; - } - - /** - * @return integer - */ - public function getInternalFileId() { - return $this->info->getId(); - } - - /** - * @param string $user - * @return int - */ - public function getSharePermissions($user) { - - // check of we access a federated share - if ($user !== null) { - try { - $share = $this->shareManager->getShareByToken($user); - return $share->getPermissions(); - } catch (ShareNotFound $e) { - // ignore - } - } - - $storage = $this->info->getStorage(); - - $path = $this->info->getInternalPath(); - - if ($storage->instanceOfStorage('\OC\Files\Storage\Shared')) { - /** @var \OC\Files\Storage\Shared $storage */ - $permissions = (int)$storage->getShare()->getPermissions(); - } else { - $permissions = $storage->getPermissions($path); - } - - /* - * We can always share non moveable mount points with DELETE and UPDATE - * Eventually we need to do this properly - */ - $mountpoint = $this->info->getMountPoint(); - if (!($mountpoint instanceof MoveableMount)) { - $mountpointpath = $mountpoint->getMountPoint(); - if (substr($mountpointpath, -1) === '/') { - $mountpointpath = substr($mountpointpath, 0, -1); - } - - if ($mountpointpath === $this->info->getPath()) { - $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE; - } - } - - /* - * Files can't have create or delete permissions - */ - if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE); - } - - return $permissions; - } - - /** - * @return string - */ - public function getDavPermissions() { - $p = ''; - if ($this->info->isShared()) { - $p .= 'S'; - } - if ($this->info->isShareable()) { - $p .= 'R'; - } - if ($this->info->isMounted()) { - $p .= 'M'; - } - if ($this->info->isDeletable()) { - $p .= 'D'; - } - if ($this->info->isUpdateable()) { - $p .= 'NV'; // Renameable, Moveable - } - if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - if ($this->info->isUpdateable()) { - $p .= 'W'; - } - } else { - if ($this->info->isCreatable()) { - $p .= 'CK'; - } - } - return $p; - } - - public function getOwner() { - return $this->info->getOwner(); - } - - protected function verifyPath() { - try { - $fileName = basename($this->info->getPath()); - $this->fileView->verifyPath($this->path, $fileName); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } - } - - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - */ - public function acquireLock($type) { - $this->fileView->lockFile($this->path, $type); - } - - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - */ - public function releaseLock($type) { - $this->fileView->unlockFile($this->path, $type); - } - - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - */ - public function changeLock($type) { - $this->fileView->changeLock($this->path, $type); - } -} diff --git a/apps/dav/lib/connector/sabre/objecttree.php b/apps/dav/lib/connector/sabre/objecttree.php deleted file mode 100644 index f38dfe679c7..00000000000 --- a/apps/dav/lib/connector/sabre/objecttree.php +++ /dev/null @@ -1,297 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCA\DAV\Connector\Sabre\Exception\Forbidden; -use OCA\DAV\Connector\Sabre\Exception\InvalidPath; -use OCA\DAV\Connector\Sabre\Exception\FileLocked; -use OC\Files\FileInfo; -use OC\Files\Mount\MoveableMount; -use OCP\Files\ForbiddenException; -use OCP\Files\StorageInvalidException; -use OCP\Files\StorageNotAvailableException; -use OCP\Lock\LockedException; - -class ObjectTree extends \Sabre\DAV\Tree { - - /** - * @var \OC\Files\View - */ - protected $fileView; - - /** - * @var \OCP\Files\Mount\IMountManager - */ - protected $mountManager; - - /** - * Creates the object - */ - public function __construct() { - } - - /** - * @param \Sabre\DAV\INode $rootNode - * @param \OC\Files\View $view - * @param \OCP\Files\Mount\IMountManager $mountManager - */ - public function init(\Sabre\DAV\INode $rootNode, \OC\Files\View $view, \OCP\Files\Mount\IMountManager $mountManager) { - $this->rootNode = $rootNode; - $this->fileView = $view; - $this->mountManager = $mountManager; - } - - /** - * If the given path is a chunked file name, converts it - * to the real file name. Only applies if the OC-CHUNKED header - * is present. - * - * @param string $path chunk file path to convert - * - * @return string path to real file - */ - private function resolveChunkFile($path) { - if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - // resolve to real file name to find the proper node - list($dir, $name) = \Sabre\HTTP\URLUtil::splitPath($path); - if ($dir == '/' || $dir == '.') { - $dir = ''; - } - - $info = \OC_FileChunking::decodeName($name); - // only replace path if it was really the chunked file - if (isset($info['transferid'])) { - // getNodePath is called for multiple nodes within a chunk - // upload call - $path = $dir . '/' . $info['name']; - $path = ltrim($path, '/'); - } - } - return $path; - } - - public function cacheNode(Node $node) { - $this->cache[trim($node->getPath(), '/')] = $node; - } - - /** - * Returns the INode object for the requested path - * - * @param string $path - * @return \Sabre\DAV\INode - * @throws InvalidPath - * @throws \Sabre\DAV\Exception\Locked - * @throws \Sabre\DAV\Exception\NotFound - * @throws \Sabre\DAV\Exception\ServiceUnavailable - */ - public function getNodeForPath($path) { - if (!$this->fileView) { - throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); - } - - $path = trim($path, '/'); - - if (isset($this->cache[$path])) { - return $this->cache[$path]; - } - - if ($path) { - try { - $this->fileView->verifyPath($path, basename($path)); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } - } - - // Is it the root node? - if (!strlen($path)) { - return $this->rootNode; - } - - if (pathinfo($path, PATHINFO_EXTENSION) === 'part') { - // read from storage - $absPath = $this->fileView->getAbsolutePath($path); - $mount = $this->fileView->getMount($path); - $storage = $mount->getStorage(); - $internalPath = $mount->getInternalPath($absPath); - if ($storage && $storage->file_exists($internalPath)) { - /** - * @var \OC\Files\Storage\Storage $storage - */ - // get data directly - $data = $storage->getMetaData($internalPath); - $info = new FileInfo($absPath, $storage, $internalPath, $data, $mount); - } else { - $info = null; - } - } else { - // resolve chunk file name to real name, if applicable - $path = $this->resolveChunkFile($path); - - // read from cache - try { - $info = $this->fileView->getFileInfo($path); - } catch (StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available'); - } catch (StorageInvalidException $e) { - throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid'); - } catch (LockedException $e) { - throw new \Sabre\DAV\Exception\Locked(); - } - } - - if (!$info) { - throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located'); - } - - if ($info->getType() === 'dir') { - $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this); - } else { - $node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info); - } - - $this->cache[$path] = $node; - return $node; - - } - - /** - * Moves a file from one location to another - * - * @param string $sourcePath The path to the file which should be moved - * @param string $destinationPath The full destination path, so not just the destination parent node - * @throws \Sabre\DAV\Exception\BadRequest - * @throws \Sabre\DAV\Exception\ServiceUnavailable - * @throws \Sabre\DAV\Exception\Forbidden - * @return int - */ - public function move($sourcePath, $destinationPath) { - if (!$this->fileView) { - throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); - } - - $targetNodeExists = $this->nodeExists($destinationPath); - $sourceNode = $this->getNodeForPath($sourcePath); - if ($sourceNode instanceof \Sabre\DAV\ICollection && $targetNodeExists) { - throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists'); - } - list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($sourcePath); - list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destinationPath); - - $isMovableMount = false; - $sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath)); - $internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath)); - if ($sourceMount instanceof MoveableMount && $internalPath === '') { - $isMovableMount = true; - } - - try { - $sameFolder = ($sourceDir === $destinationDir); - // if we're overwriting or same folder - if ($targetNodeExists || $sameFolder) { - // note that renaming a share mount point is always allowed - if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - } else { - if (!$this->fileView->isCreatable($destinationDir)) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - } - - if (!$sameFolder) { - // moving to a different folder, source will be gone, like a deletion - // note that moving a share mount point is always allowed - if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) { - throw new \Sabre\DAV\Exception\Forbidden(); - } - } - - $fileName = basename($destinationPath); - try { - $this->fileView->verifyPath($destinationDir, $fileName); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } - - $renameOkay = $this->fileView->rename($sourcePath, $destinationPath); - if (!$renameOkay) { - throw new \Sabre\DAV\Exception\Forbidden(''); - } - } catch (StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } catch (ForbiddenException $ex) { - throw new Forbidden($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - $this->markDirty($sourceDir); - $this->markDirty($destinationDir); - - } - - /** - * Copies a file or directory. - * - * This method must work recursively and delete the destination - * if it exists - * - * @param string $source - * @param string $destination - * @throws \Sabre\DAV\Exception\ServiceUnavailable - * @return void - */ - public function copy($source, $destination) { - if (!$this->fileView) { - throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); - } - - // this will trigger existence check - $this->getNodeForPath($source); - - list($destinationDir, $destinationName) = \Sabre\HTTP\URLUtil::splitPath($destination); - try { - $this->fileView->verifyPath($destinationDir, $destinationName); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } - - try { - $this->fileView->copy($source, $destination); - } catch (StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } catch (ForbiddenException $ex) { - throw new Forbidden($ex->getMessage(), $ex->getRetry()); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination); - $this->markDirty($destinationDir); - } -} diff --git a/apps/dav/lib/connector/sabre/principal.php b/apps/dav/lib/connector/sabre/principal.php deleted file mode 100644 index 787bcdf469b..00000000000 --- a/apps/dav/lib/connector/sabre/principal.php +++ /dev/null @@ -1,234 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Jakob Sack <mail@jakobsack.de> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCP\IGroup; -use OCP\IGroupManager; -use OCP\IUser; -use OCP\IUserManager; -use Sabre\DAV\Exception; -use \Sabre\DAV\PropPatch; -use Sabre\DAVACL\PrincipalBackend\BackendInterface; -use Sabre\HTTP\URLUtil; - -class Principal implements BackendInterface { - - /** @var IUserManager */ - private $userManager; - - /** @var IGroupManager */ - private $groupManager; - - /** @var string */ - private $principalPrefix; - - /** @var bool */ - private $hasGroups; - - /** - * @param IUserManager $userManager - * @param IGroupManager $groupManager - * @param string $principalPrefix - */ - public function __construct(IUserManager $userManager, - IGroupManager $groupManager, - $principalPrefix = 'principals/users/') { - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->principalPrefix = trim($principalPrefix, '/'); - $this->hasGroups = ($principalPrefix === 'principals/users/'); - } - - /** - * Returns a list of principals based on a prefix. - * - * This prefix will often contain something like 'principals'. You are only - * expected to return principals that are in this base path. - * - * You are expected to return at least a 'uri' for every user, you can - * return any additional properties if you wish so. Common properties are: - * {DAV:}displayname - * - * @param string $prefixPath - * @return string[] - */ - public function getPrincipalsByPrefix($prefixPath) { - $principals = []; - - if ($prefixPath === $this->principalPrefix) { - foreach($this->userManager->search('') as $user) { - $principals[] = $this->userToPrincipal($user); - } - } - - return $principals; - } - - /** - * Returns a specific principal, specified by it's path. - * The returned structure should be the exact same as from - * getPrincipalsByPrefix. - * - * @param string $path - * @return array - */ - public function getPrincipalByPath($path) { - list($prefix, $name) = URLUtil::splitPath($path); - - if ($prefix === $this->principalPrefix) { - $user = $this->userManager->get($name); - - if (!is_null($user)) { - return $this->userToPrincipal($user); - } - } - return null; - } - - /** - * Returns the list of members for a group-principal - * - * @param string $principal - * @return string[] - * @throws Exception - */ - public function getGroupMemberSet($principal) { - // TODO: for now the group principal has only one member, the user itself - $principal = $this->getPrincipalByPath($principal); - if (!$principal) { - throw new Exception('Principal not found'); - } - - return [$principal['uri']]; - } - - /** - * Returns the list of groups a principal is a member of - * - * @param string $principal - * @param bool $needGroups - * @return array - * @throws Exception - */ - public function getGroupMembership($principal, $needGroups = false) { - list($prefix, $name) = URLUtil::splitPath($principal); - - if ($prefix === $this->principalPrefix) { - $user = $this->userManager->get($name); - if (!$user) { - throw new Exception('Principal not found'); - } - - if ($this->hasGroups || $needGroups) { - $groups = $this->groupManager->getUserGroups($user); - $groups = array_map(function($group) { - /** @var IGroup $group */ - return 'principals/groups/' . $group->getGID(); - }, $groups); - - return $groups; - } - } - return []; - } - - /** - * Updates the list of group members for a group principal. - * - * The principals should be passed as a list of uri's. - * - * @param string $principal - * @param string[] $members - * @throws Exception - */ - public function setGroupMemberSet($principal, array $members) { - throw new Exception('Setting members of the group is not supported yet'); - } - - /** - * @param string $path - * @param PropPatch $propPatch - * @return int - */ - function updatePrincipal($path, PropPatch $propPatch) { - return 0; - } - - /** - * @param string $prefixPath - * @param array $searchProperties - * @param string $test - * @return array - */ - function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { - return []; - } - - /** - * @param string $uri - * @param string $principalPrefix - * @return string - */ - function findByUri($uri, $principalPrefix) { - if (substr($uri, 0, 7) === 'mailto:') { - $email = substr($uri, 7); - $users = $this->userManager->getByEmail($email); - if (count($users) === 1) { - return $this->principalPrefix . '/' . $users[0]->getUID(); - } - } - - return ''; - } - - /** - * @param IUser $user - * @return array - */ - protected function userToPrincipal($user) { - $userId = $user->getUID(); - $displayName = $user->getDisplayName(); - $principal = [ - 'uri' => $this->principalPrefix . '/' . $userId, - '{DAV:}displayname' => is_null($displayName) ? $userId : $displayName, - ]; - - $email = $user->getEMailAddress(); - if (!empty($email)) { - $principal['{http://sabredav.org/ns}email-address'] = $email; - return $principal; - } - return $principal; - } - - public function getPrincipalPrefix() { - return $this->principalPrefix; - } - -} diff --git a/apps/dav/lib/connector/sabre/quotaplugin.php b/apps/dav/lib/connector/sabre/quotaplugin.php deleted file mode 100644 index a093c52851c..00000000000 --- a/apps/dav/lib/connector/sabre/quotaplugin.php +++ /dev/null @@ -1,146 +0,0 @@ -<?php -/** - * @author Felix Moeller <mail@felixmoeller.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author scambra <sergio@entrecables.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre; - -/** - * This plugin check user quota and deny creating files when they exceeds the quota. - * - * @author Sergio Cambra - * @copyright Copyright (C) 2012 entreCables S.L. All rights reserved. - * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License - */ -class QuotaPlugin extends \Sabre\DAV\ServerPlugin { - - /** - * @var \OC\Files\View - */ - private $view; - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @param \OC\Files\View $view - */ - public function __construct($view) { - $this->view = $view; - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the requires event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - - $this->server = $server; - - $server->on('beforeWriteContent', array($this, 'checkQuota'), 10); - $server->on('beforeCreateFile', array($this, 'checkQuota'), 10); - } - - /** - * This method is called before any HTTP method and validates there is enough free space to store the file - * - * @param string $uri - * @param null $data - * @throws \Sabre\DAV\Exception\InsufficientStorage - * @return bool - */ - public function checkQuota($uri, $data = null) { - $length = $this->getLength(); - if ($length) { - if (substr($uri, 0, 1) !== '/') { - $uri = '/' . $uri; - } - list($parentUri, $newName) = \Sabre\HTTP\URLUtil::splitPath($uri); - if(is_null($parentUri)) { - $parentUri = ''; - } - $req = $this->server->httpRequest; - if ($req->getHeader('OC-Chunked')) { - $info = \OC_FileChunking::decodeName($newName); - $chunkHandler = $this->getFileChunking($info); - // subtract the already uploaded size to see whether - // there is still enough space for the remaining chunks - $length -= $chunkHandler->getCurrentSize(); - // use target file name for free space check in case of shared files - $uri = rtrim($parentUri, '/') . '/' . $info['name']; - } - $freeSpace = $this->getFreeSpace($uri); - if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN && $length > $freeSpace) { - if (isset($chunkHandler)) { - $chunkHandler->cleanup(); - } - throw new \Sabre\DAV\Exception\InsufficientStorage(); - } - } - return true; - } - - public function getFileChunking($info) { - // FIXME: need a factory for better mocking support - return new \OC_FileChunking($info); - } - - public function getLength() { - $req = $this->server->httpRequest; - $length = $req->getHeader('X-Expected-Entity-Length'); - if (!$length) { - $length = $req->getHeader('Content-Length'); - } - - $ocLength = $req->getHeader('OC-Total-Length'); - if ($length && $ocLength) { - return max($length, $ocLength); - } - - return $length; - } - - /** - * @param string $uri - * @return mixed - */ - public function getFreeSpace($uri) { - try { - $freeSpace = $this->view->free_space(ltrim($uri, '/')); - return $freeSpace; - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } - } -} diff --git a/apps/dav/lib/connector/sabre/server.php b/apps/dav/lib/connector/sabre/server.php deleted file mode 100644 index 421fc64422d..00000000000 --- a/apps/dav/lib/connector/sabre/server.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author scolebrook <scolebrook@mac.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -/** - * Class \OCA\DAV\Connector\Sabre\Server - * - * This class overrides some methods from @see \Sabre\DAV\Server. - * - * @see \Sabre\DAV\Server - */ -class Server extends \Sabre\DAV\Server { - - /** - * @see \Sabre\DAV\Server - */ - public function __construct($treeOrNode = null) { - parent::__construct($treeOrNode); - self::$exposeVersion = false; - $this->enablePropfindDepthInfinity = true; - } -} diff --git a/apps/dav/lib/connector/sabre/serverfactory.php b/apps/dav/lib/connector/sabre/serverfactory.php deleted file mode 100644 index 5853370778d..00000000000 --- a/apps/dav/lib/connector/sabre/serverfactory.php +++ /dev/null @@ -1,184 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use OCA\DAV\Files\BrowserErrorPagePlugin; -use OCP\Files\Mount\IMountManager; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\ILogger; -use OCP\IRequest; -use OCP\ITagManager; -use OCP\IUserSession; -use Sabre\DAV\Auth\Backend\BackendInterface; - -class ServerFactory { - /** @var IConfig */ - private $config; - /** @var ILogger */ - private $logger; - /** @var IDBConnection */ - private $databaseConnection; - /** @var IUserSession */ - private $userSession; - /** @var IMountManager */ - private $mountManager; - /** @var ITagManager */ - private $tagManager; - /** @var IRequest */ - private $request; - - /** - * @param IConfig $config - * @param ILogger $logger - * @param IDBConnection $databaseConnection - * @param IUserSession $userSession - * @param IMountManager $mountManager - * @param ITagManager $tagManager - * @param IRequest $request - */ - public function __construct( - IConfig $config, - ILogger $logger, - IDBConnection $databaseConnection, - IUserSession $userSession, - IMountManager $mountManager, - ITagManager $tagManager, - IRequest $request - ) { - $this->config = $config; - $this->logger = $logger; - $this->databaseConnection = $databaseConnection; - $this->userSession = $userSession; - $this->mountManager = $mountManager; - $this->tagManager = $tagManager; - $this->request = $request; - } - - /** - * @param string $baseUri - * @param string $requestUri - * @param BackendInterface $authBackend - * @param callable $viewCallBack callback that should return the view for the dav endpoint - * @return Server - */ - public function createServer($baseUri, - $requestUri, - BackendInterface $authBackend, - callable $viewCallBack) { - // Fire up server - $objectTree = new \OCA\DAV\Connector\Sabre\ObjectTree(); - $server = new \OCA\DAV\Connector\Sabre\Server($objectTree); - // Set URL explicitly due to reverse-proxy situations - $server->httpRequest->setUrl($requestUri); - $server->setBaseUri($baseUri); - - // Load plugins - $defaults = new \OC_Defaults(); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\MaintenancePlugin($this->config)); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin($this->config)); - $server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName())); - // FIXME: The following line is a workaround for legacy components relying on being able to send a GET to / - $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()); - // Some WebDAV clients do require Class 2 WebDAV support (locking), since - // we do not provide locking we emulate it using a fake locking plugin. - if($this->request->isUserAgent([ - '/WebDAVFS/', - '/Microsoft Office OneNote 2013/', - '/Microsoft-WebDAV-MiniRedir/', - ])) { - $server->addPlugin(new \OCA\DAV\Connector\Sabre\FakeLockerPlugin()); - } - - if (BrowserErrorPagePlugin::isBrowserRequest($this->request)) { - $server->addPlugin(new BrowserErrorPagePlugin()); - } - - // wait with registering these until auth is handled and the filesystem is setup - $server->on('beforeMethod', function () use ($server, $objectTree, $viewCallBack) { - // ensure the skeleton is copied - $userFolder = \OC::$server->getUserFolder(); - - /** @var \OC\Files\View $view */ - $view = $viewCallBack($server); - $rootInfo = $view->getFileInfo(''); - - // Create ownCloud Dir - if ($rootInfo->getType() === 'dir') { - $root = new \OCA\DAV\Connector\Sabre\Directory($view, $rootInfo, $objectTree); - } else { - $root = new \OCA\DAV\Connector\Sabre\File($view, $rootInfo); - } - $objectTree->init($root, $view, $this->mountManager); - - $server->addPlugin( - new \OCA\DAV\Connector\Sabre\FilesPlugin( - $objectTree, - $view, - $this->config, - false, - !$this->config->getSystemValue('debug', false) - ) - ); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\QuotaPlugin($view)); - - if($this->userSession->isLoggedIn()) { - $server->addPlugin(new \OCA\DAV\Connector\Sabre\TagsPlugin($objectTree, $this->tagManager)); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\SharesPlugin( - $objectTree, - $this->userSession, - $userFolder, - \OC::$server->getShareManager() - )); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\CommentPropertiesPlugin(\OC::$server->getCommentsManager(), $this->userSession)); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesReportPlugin( - $objectTree, - $view, - \OC::$server->getSystemTagManager(), - \OC::$server->getSystemTagObjectMapper(), - $this->userSession, - \OC::$server->getGroupManager(), - $userFolder - )); - // custom properties plugin must be the last one - $server->addPlugin( - new \Sabre\DAV\PropertyStorage\Plugin( - new \OCA\DAV\Connector\Sabre\CustomPropertiesBackend( - $objectTree, - $this->databaseConnection, - $this->userSession->getUser() - ) - ) - ); - } - $server->addPlugin(new \OCA\DAV\Connector\Sabre\CopyEtagHeaderPlugin()); - }, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request - return $server; - } -} diff --git a/apps/dav/lib/connector/sabre/sharesplugin.php b/apps/dav/lib/connector/sabre/sharesplugin.php deleted file mode 100644 index c76068969e9..00000000000 --- a/apps/dav/lib/connector/sabre/sharesplugin.php +++ /dev/null @@ -1,177 +0,0 @@ -<?php -/** - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre; - -use \Sabre\DAV\PropFind; -use \Sabre\DAV\PropPatch; -use OCP\IUserSession; -use OCP\Share\IShare; -use OCA\DAV\Connector\Sabre\ShareTypeList; - -/** - * Sabre Plugin to provide share-related properties - */ -class SharesPlugin extends \Sabre\DAV\ServerPlugin { - - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - const SHARETYPES_PROPERTYNAME = '{http://owncloud.org/ns}share-types'; - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var \OCP\Share\IManager - */ - private $shareManager; - - /** - * @var \Sabre\DAV\Tree - */ - private $tree; - - /** - * @var string - */ - private $userId; - - /** - * @var \OCP\Files\Folder - */ - private $userFolder; - - /** - * @var IShare[] - */ - private $cachedShareTypes; - - /** - * @param \Sabre\DAV\Tree $tree tree - * @param IUserSession $userSession user session - * @param \OCP\Files\Folder $userFolder user home folder - * @param \OCP\Share\IManager $shareManager share manager - */ - public function __construct( - \Sabre\DAV\Tree $tree, - IUserSession $userSession, - \OCP\Files\Folder $userFolder, - \OCP\Share\IManager $shareManager - ) { - $this->tree = $tree; - $this->shareManager = $shareManager; - $this->userFolder = $userFolder; - $this->userId = $userSession->getUser()->getUID(); - $this->cachedShareTypes = []; - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - */ - public function initialize(\Sabre\DAV\Server $server) { - $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc'; - $server->xml->elementMap[self::SHARETYPES_PROPERTYNAME] = 'OCA\\DAV\\Connector\\Sabre\\ShareTypeList'; - $server->protectedProperties[] = self::SHARETYPES_PROPERTYNAME; - - $this->server = $server; - $this->server->on('propFind', array($this, 'handleGetProperties')); - } - - /** - * Return a list of share types for outgoing shares - * - * @param \OCP\Files\Node $node file node - * - * @return int[] array of share types - */ - private function getShareTypes(\OCP\Files\Node $node) { - $shareTypes = []; - $requestedShareTypes = [ - \OCP\Share::SHARE_TYPE_USER, - \OCP\Share::SHARE_TYPE_GROUP, - \OCP\Share::SHARE_TYPE_LINK, - \OCP\Share::SHARE_TYPE_REMOTE - ]; - foreach ($requestedShareTypes as $requestedShareType) { - // one of each type is enough to find out about the types - $shares = $this->shareManager->getSharesBy( - $this->userId, - $requestedShareType, - $node, - false, - 1 - ); - if (!empty($shares)) { - $shareTypes[] = $requestedShareType; - } - } - return $shareTypes; - } - - /** - * Adds shares to propfind response - * - * @param PropFind $propFind propfind object - * @param \Sabre\DAV\INode $sabreNode sabre node - */ - public function handleGetProperties( - PropFind $propFind, - \Sabre\DAV\INode $sabreNode - ) { - if (!($sabreNode instanceof \OCA\DAV\Connector\Sabre\Node)) { - return; - } - - // need prefetch ? - if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory - && $propFind->getDepth() !== 0 - && !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME)) - ) { - $folderNode = $this->userFolder->get($propFind->getPath()); - $children = $folderNode->getDirectoryListing(); - - $this->cachedShareTypes[$folderNode->getId()] = $this->getShareTypes($folderNode); - foreach ($children as $childNode) { - $this->cachedShareTypes[$childNode->getId()] = $this->getShareTypes($childNode); - } - } - - $propFind->handle(self::SHARETYPES_PROPERTYNAME, function() use ($sabreNode) { - if (isset($this->cachedShareTypes[$sabreNode->getId()])) { - $shareTypes = $this->cachedShareTypes[$sabreNode->getId()]; - } else { - $node = $this->userFolder->get($sabreNode->getPath()); - $shareTypes = $this->getShareTypes($node); - } - - return new ShareTypeList($shareTypes); - }); - } -} diff --git a/apps/dav/lib/connector/sabre/sharetypelist.php b/apps/dav/lib/connector/sabre/sharetypelist.php deleted file mode 100644 index 763586412ad..00000000000 --- a/apps/dav/lib/connector/sabre/sharetypelist.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php -/** - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use Sabre\Xml\Element; -use Sabre\Xml\Reader; -use Sabre\Xml\Writer; - -/** - * ShareTypeList property - * - * This property contains multiple "share-type" elements, each containing a share type. - */ -class ShareTypeList implements Element { - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - - /** - * Share types - * - * @var int[] - */ - private $shareTypes; - - /** - * @param int[] $shareTypes - */ - public function __construct($shareTypes) { - $this->shareTypes = $shareTypes; - } - - /** - * Returns the share types - * - * @return int[] - */ - public function getShareTypes() { - return $this->shareTypes; - } - - /** - * The deserialize method is called during xml parsing. - * - * @param Reader $reader - * @return mixed - */ - static function xmlDeserialize(Reader $reader) { - $shareTypes = []; - - foreach ($reader->parseInnerTree() as $elem) { - if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') { - $shareTypes[] = (int)$elem['value']; - } - } - return new self($shareTypes); - } - - /** - * The xmlSerialize metod is called during xml writing. - * - * @param Writer $writer - * @return void - */ - function xmlSerialize(Writer $writer) { - foreach ($this->shareTypes as $shareType) { - $writer->writeElement('{' . self::NS_OWNCLOUD . '}share-type', $shareType); - } - } -} diff --git a/apps/dav/lib/connector/sabre/taglist.php b/apps/dav/lib/connector/sabre/taglist.php deleted file mode 100644 index 5c1cd8b4f1d..00000000000 --- a/apps/dav/lib/connector/sabre/taglist.php +++ /dev/null @@ -1,120 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ - -namespace OCA\DAV\Connector\Sabre; - -use Sabre\Xml\Element; -use Sabre\Xml\Reader; -use Sabre\Xml\Writer; - -/** - * TagList property - * - * This property contains multiple "tag" elements, each containing a tag name. - */ -class TagList implements Element { - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - - /** - * tags - * - * @var array - */ - private $tags; - - /** - * @param array $tags - */ - public function __construct(array $tags) { - $this->tags = $tags; - } - - /** - * Returns the tags - * - * @return array - */ - public function getTags() { - - return $this->tags; - - } - - /** - * The deserialize method is called during xml parsing. - * - * This method is called statictly, this is because in theory this method - * may be used as a type of constructor, or factory method. - * - * Often you want to return an instance of the current class, but you are - * free to return other data as well. - * - * You are responsible for advancing the reader to the next element. Not - * doing anything will result in a never-ending loop. - * - * If you just want to skip parsing for this element altogether, you can - * just call $reader->next(); - * - * $reader->parseInnerTree() will parse the entire sub-tree, and advance to - * the next element. - * - * @param Reader $reader - * @return mixed - */ - static function xmlDeserialize(Reader $reader) { - $tags = []; - - foreach ($reader->parseInnerTree() as $elem) { - if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') { - $tags[] = $elem['value']; - } - } - return new self($tags); - } - - /** - * The xmlSerialize metod is called during xml writing. - * - * Use the $writer argument to write its own xml serialization. - * - * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered - * its 'inner xml'. - * - * The parent of the current element is responsible for writing a - * containing element. - * - * This allows serializers to be re-used for different element names. - * - * If you are opening new elements, you must also close them again. - * - * @param Writer $writer - * @return void - */ - function xmlSerialize(Writer $writer) { - - foreach ($this->tags as $tag) { - $writer->writeElement('{' . self::NS_OWNCLOUD . '}tag', $tag); - } - } -} diff --git a/apps/dav/lib/connector/sabre/tagsplugin.php b/apps/dav/lib/connector/sabre/tagsplugin.php deleted file mode 100644 index dfc1a2dd95d..00000000000 --- a/apps/dav/lib/connector/sabre/tagsplugin.php +++ /dev/null @@ -1,293 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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/> - * - */ -namespace OCA\DAV\Connector\Sabre; - -/** - * ownCloud - * - * @author Vincent Petry - * @copyright 2014 Vincent Petry <pvince81@owncloud.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -use \Sabre\DAV\PropFind; -use \Sabre\DAV\PropPatch; - -class TagsPlugin extends \Sabre\DAV\ServerPlugin -{ - - // namespace - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - const TAGS_PROPERTYNAME = '{http://owncloud.org/ns}tags'; - const FAVORITE_PROPERTYNAME = '{http://owncloud.org/ns}favorite'; - const TAG_FAVORITE = '_$!<Favorite>!$_'; - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var \OCP\ITagManager - */ - private $tagManager; - - /** - * @var \OCP\ITags - */ - private $tagger; - - /** - * Array of file id to tags array - * The null value means the cache wasn't initialized. - * - * @var array - */ - private $cachedTags; - - /** - * @var \Sabre\DAV\Tree - */ - private $tree; - - /** - * @param \Sabre\DAV\Tree $tree tree - * @param \OCP\ITagManager $tagManager tag manager - */ - public function __construct(\Sabre\DAV\Tree $tree, \OCP\ITagManager $tagManager) { - $this->tree = $tree; - $this->tagManager = $tagManager; - $this->tagger = null; - $this->cachedTags = array(); - } - - /** - * This initializes the plugin. - * - * This function is called by \Sabre\DAV\Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param \Sabre\DAV\Server $server - * @return void - */ - public function initialize(\Sabre\DAV\Server $server) { - - $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc'; - $server->xml->elementMap[self::TAGS_PROPERTYNAME] = 'OCA\\DAV\\Connector\\Sabre\\TagList'; - - $this->server = $server; - $this->server->on('propFind', array($this, 'handleGetProperties')); - $this->server->on('propPatch', array($this, 'handleUpdateProperties')); - } - - /** - * Returns the tagger - * - * @return \OCP\ITags tagger - */ - private function getTagger() { - if (!$this->tagger) { - $this->tagger = $this->tagManager->load('files'); - } - return $this->tagger; - } - - /** - * Returns tags and favorites. - * - * @param integer $fileId file id - * @return array list($tags, $favorite) with $tags as tag array - * and $favorite is a boolean whether the file was favorited - */ - private function getTagsAndFav($fileId) { - $isFav = false; - $tags = $this->getTags($fileId); - if ($tags) { - $favPos = array_search(self::TAG_FAVORITE, $tags); - if ($favPos !== false) { - $isFav = true; - unset($tags[$favPos]); - } - } - return array($tags, $isFav); - } - - /** - * Returns tags for the given file id - * - * @param integer $fileId file id - * @return array list of tags for that file - */ - private function getTags($fileId) { - if (isset($this->cachedTags[$fileId])) { - return $this->cachedTags[$fileId]; - } else { - $tags = $this->getTagger()->getTagsForObjects(array($fileId)); - if ($tags !== false) { - if (empty($tags)) { - return array(); - } - return current($tags); - } - } - return null; - } - - /** - * Updates the tags of the given file id - * - * @param int $fileId - * @param array $tags array of tag strings - */ - private function updateTags($fileId, $tags) { - $tagger = $this->getTagger(); - $currentTags = $this->getTags($fileId); - - $newTags = array_diff($tags, $currentTags); - foreach ($newTags as $tag) { - if ($tag === self::TAG_FAVORITE) { - continue; - } - $tagger->tagAs($fileId, $tag); - } - $deletedTags = array_diff($currentTags, $tags); - foreach ($deletedTags as $tag) { - if ($tag === self::TAG_FAVORITE) { - continue; - } - $tagger->unTag($fileId, $tag); - } - } - - /** - * Adds tags and favorites properties to the response, - * if requested. - * - * @param PropFind $propFind - * @param \Sabre\DAV\INode $node - * @return void - */ - public function handleGetProperties( - PropFind $propFind, - \Sabre\DAV\INode $node - ) { - if (!($node instanceof \OCA\DAV\Connector\Sabre\Node)) { - return; - } - - // need prefetch ? - if ($node instanceof \OCA\DAV\Connector\Sabre\Directory - && $propFind->getDepth() !== 0 - && (!is_null($propFind->getStatus(self::TAGS_PROPERTYNAME)) - || !is_null($propFind->getStatus(self::FAVORITE_PROPERTYNAME)) - )) { - // note: pre-fetching only supported for depth <= 1 - $folderContent = $node->getChildren(); - $fileIds[] = (int)$node->getId(); - foreach ($folderContent as $info) { - $fileIds[] = (int)$info->getId(); - } - $tags = $this->getTagger()->getTagsForObjects($fileIds); - if ($tags === false) { - // the tags API returns false on error... - $tags = array(); - } - - $this->cachedTags = $this->cachedTags + $tags; - $emptyFileIds = array_diff($fileIds, array_keys($tags)); - // also cache the ones that were not found - foreach ($emptyFileIds as $fileId) { - $this->cachedTags[$fileId] = []; - } - } - - $tags = null; - $isFav = null; - - $propFind->handle(self::TAGS_PROPERTYNAME, function() use ($tags, &$isFav, $node) { - list($tags, $isFav) = $this->getTagsAndFav($node->getId()); - return new TagList($tags); - }); - - $propFind->handle(self::FAVORITE_PROPERTYNAME, function() use ($isFav, $node) { - if (is_null($isFav)) { - list(, $isFav) = $this->getTagsAndFav($node->getId()); - } - return $isFav; - }); - } - - /** - * Updates tags and favorites properties, if applicable. - * - * @param string $path - * @param PropPatch $propPatch - * - * @return void - */ - public function handleUpdateProperties($path, PropPatch $propPatch) { - $propPatch->handle(self::TAGS_PROPERTYNAME, function($tagList) use ($path) { - $node = $this->tree->getNodeForPath($path); - if (is_null($node)) { - return 404; - } - $this->updateTags($node->getId(), $tagList->getTags()); - return true; - }); - - $propPatch->handle(self::FAVORITE_PROPERTYNAME, function($favState) use ($path) { - $node = $this->tree->getNodeForPath($path); - if (is_null($node)) { - return 404; - } - if ((int)$favState === 1 || $favState === 'true') { - $this->getTagger()->tagAs($node->getId(), self::TAG_FAVORITE); - } else { - $this->getTagger()->unTag($node->getId(), self::TAG_FAVORITE); - } - - if (is_null($favState)) { - // confirm deletion - return 204; - } - - return 200; - }); - } -} |