diff options
Diffstat (limited to 'lib/private/connector')
25 files changed, 0 insertions, 3872 deletions
diff --git a/lib/private/connector/sabre/appenabledplugin.php b/lib/private/connector/sabre/appenabledplugin.php deleted file mode 100644 index 696a9fcb81f..00000000000 --- a/lib/private/connector/sabre/appenabledplugin.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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/lib/private/connector/sabre/auth.php b/lib/private/connector/sabre/auth.php deleted file mode 100644 index d33ffad7d5c..00000000000 --- a/lib/private/connector/sabre/auth.php +++ /dev/null @@ -1,150 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Christian Seiler <christian@iwakd.de> - * @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 Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use Exception; -use Sabre\DAV\Auth\Backend\AbstractBasic; -use Sabre\DAV\Exception\NotAuthenticated; -use Sabre\DAV\Exception\ServiceUnavailable; - -class Auth extends AbstractBasic { - const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND'; - - /** - * 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 - */ - protected function isDavAuthenticated($username) { - return !is_null(\OC::$server->getSession()->get(self::DAV_AUTHENTICATED)) && - \OC::$server->getSession()->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 (\OC_User::isLoggedIn() && - $this->isDavAuthenticated(\OC_User::getUser()) - ) { - \OC_Util::setupFS(\OC_User::getUser()); - \OC::$server->getSession()->close(); - return true; - } else { - \OC_Util::setUpFS(); //login hooks may need early access to the filesystem - if(\OC_User::login($username, $password)) { - // make sure we use ownCloud's internal username here - // and not the HTTP auth supplied one, see issue #14048 - $ocUser = \OC_User::getUser(); - \OC_Util::setUpFS($ocUser); - \OC::$server->getSession()->set(self::DAV_AUTHENTICATED, $ocUser); - \OC::$server->getSession()->close(); - return true; - } else { - \OC::$server->getSession()->close(); - return false; - } - } - } - - /** - * Returns information about the currently logged in username. - * - * If nobody is currently logged in, this method should return null. - * - * @return string|null - */ - public function getCurrentUser() { - $user = \OC_User::getUser(); - if($user && $this->isDavAuthenticated($user)) { - return $user; - } - return null; - } - - /** - * Override function here. We want to cache authentication cookies - * in the syncing client to avoid HTTP-401 roundtrips. - * If the sync client supplies the cookies, then OC_User::isLoggedIn() - * will return true and we can see this WebDAV request as already authenticated, - * even if there are no HTTP Basic Auth headers. - * In other case, just fallback to the parent implementation. - * - * @param \Sabre\DAV\Server $server - * @param string $realm - * @return bool - * @throws ServiceUnavailable - */ - public function authenticate(\Sabre\DAV\Server $server, $realm) { - - try { - $result = $this->auth($server, $realm); - return $result; - } catch (NotAuthenticated $e) { - throw $e; - } catch (Exception $e) { - $class = get_class($e); - $msg = $e->getMessage(); - throw new ServiceUnavailable("$class: $msg"); - } - } - - /** - * @param \Sabre\DAV\Server $server - * @param $realm - * @return bool - */ - private function auth(\Sabre\DAV\Server $server, $realm) { - if (\OC_User::handleApacheAuth() || - (\OC_User::isLoggedIn() && is_null(\OC::$server->getSession()->get(self::DAV_AUTHENTICATED))) - ) { - $user = \OC_User::getUser(); - \OC_Util::setupFS($user); - $this->currentUser = $user; - \OC::$server->getSession()->close(); - return true; - } - - return parent::authenticate($server, $realm); - } -} diff --git a/lib/private/connector/sabre/blocklegacyclientplugin.php b/lib/private/connector/sabre/blocklegacyclientplugin.php deleted file mode 100644 index 9480cd1f06d..00000000000 --- a/lib/private/connector/sabre/blocklegacyclientplugin.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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 OC\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/lib/private/connector/sabre/copyetagheaderplugin.php b/lib/private/connector/sabre/copyetagheaderplugin.php deleted file mode 100644 index fe1a8fab70e..00000000000 --- a/lib/private/connector/sabre/copyetagheaderplugin.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/** - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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/lib/private/connector/sabre/custompropertiesbackend.php b/lib/private/connector/sabre/custompropertiesbackend.php deleted file mode 100644 index a05de1adb35..00000000000 --- a/lib/private/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) 2015, 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 OC\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/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php deleted file mode 100644 index 0261ab18047..00000000000 --- a/lib/private/connector/sabre/directory.php +++ /dev/null @@ -1,276 +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) 2015, 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 OC\Connector\Sabre; - -use OC\Connector\Sabre\Exception\InvalidPath; -use OC\Connector\Sabre\Exception\FileLocked; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; -use Sabre\DAV\Exception\Locked; - -class Directory extends \OC\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; - - /** - * 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 \OC\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 (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 (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 \OC\Connector\Sabre\Directory($this->fileView, $info); - } else { - $node = new \OC\Connector\Sabre\File($this->fileView, $info); - } - 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 (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); - $this->quotaInfo = array( - $storageInfo['used'], - $storageInfo['free'] - ); - return $this->quotaInfo; - } catch (\OCP\Files\StorageNotAvailableException $e) { - return array(0, 0); - } - } - -} diff --git a/lib/private/connector/sabre/dummygetresponseplugin.php b/lib/private/connector/sabre/dummygetresponseplugin.php deleted file mode 100644 index 6f5a009d084..00000000000 --- a/lib/private/connector/sabre/dummygetresponseplugin.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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 OC\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/lib/private/connector/sabre/exception/entitytoolarge.php b/lib/private/connector/sabre/exception/entitytoolarge.php deleted file mode 100644 index e9699deeaf1..00000000000 --- a/lib/private/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) 2015, 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 OC\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/lib/private/connector/sabre/exception/filelocked.php b/lib/private/connector/sabre/exception/filelocked.php deleted file mode 100644 index 1657a7ae376..00000000000 --- a/lib/private/connector/sabre/exception/filelocked.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Owen Winkler <a_github@midnightcircus.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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/lib/private/connector/sabre/exception/invalidpath.php b/lib/private/connector/sabre/exception/invalidpath.php deleted file mode 100644 index 6d84078fb1c..00000000000 --- a/lib/private/connector/sabre/exception/invalidpath.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2015, 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 OC\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/lib/private/connector/sabre/exception/unsupportedmediatype.php b/lib/private/connector/sabre/exception/unsupportedmediatype.php deleted file mode 100644 index b7e8594427f..00000000000 --- a/lib/private/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) 2015, 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 OC\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/lib/private/connector/sabre/exceptionloggerplugin.php b/lib/private/connector/sabre/exceptionloggerplugin.php deleted file mode 100644 index 3f53431c8a1..00000000000 --- a/lib/private/connector/sabre/exceptionloggerplugin.php +++ /dev/null @@ -1,107 +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) 2015, 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 OC\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"; - } - - $exception = [ - 'Message' => $message, - 'Exception' => $exceptionClass, - 'Code' => $ex->getCode(), - 'Trace' => $ex->getTraceAsString(), - 'File' => $ex->getFile(), - 'Line' => $ex->getLine(), - ]; - $this->logger->log($level, 'Exception: ' . json_encode($exception), ['app' => $this->appName]); - } -} diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php deleted file mode 100644 index f4acc8290bc..00000000000 --- a/lib/private/connector/sabre/file.php +++ /dev/null @@ -1,499 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <schiessle@owncloud.com> - * @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 Owen Winkler <a_github@midnightcircus.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <rmccorkell@karoshi.org.uk> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use OC\Connector\Sabre\Exception\EntityTooLarge; -use OC\Connector\Sabre\Exception\FileLocked; -use OC\Connector\Sabre\Exception\UnsupportedMediaType; -use OC\Files\Filesystem; -use OCP\Encryption\Exceptions\GenericEncryptionException; -use OCP\Files\EntityTooLargeException; -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->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,) = \OC_Helper::streamCopy($data, $target); - fclose($target); - - // 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'] !== 'LOCK') { - $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 (\Exception $e) { - $partStorage->unlink($internalPartPath); - $this->convertToSabreException($e); - } - } - - try { - $this->changeLock(ILockingProvider::LOCK_SHARED); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - // since we skipped the view we need to scan and emit the hooks ourselves - $this->fileView->getUpdater()->update($this->path); - - 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(); - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage()); - } - - return '"' . $this->info->getEtag() . '"'; - } - - 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; - } - - 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 string|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 (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 (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 mixed - */ - 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_Helper::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->emitPreHooks($exists, $targetPath); - - $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE); - - if ($needsPartFile) { - // we first assembly the target file as a part file - $partFile = $path . '/' . $info['name'] . '.ocTransferId' . $info['transferid'] . '.part'; - - - list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile); - - - $chunk_handler->file_assemble($partStorage, $partInternalPath, $this->fileView->getAbsolutePath($targetPath)); - - // here is the final atomic rename - $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath); - - $fileExists = $this->fileView->file_exists($targetPath); - 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->changeLock(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, $this->fileView->getAbsolutePath($targetPath)); - } - - // 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'); - } - } - - $this->changeLock(ILockingProvider::LOCK_SHARED); - - // since we skipped the view we need to scan and emit the hooks ourselves - $this->fileView->getUpdater()->update($targetPath); - - $this->emitPostHooks($exists, $targetPath); - - $info = $this->fileView->getFileInfo($targetPath); - 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 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); - } -} diff --git a/lib/private/connector/sabre/filesplugin.php b/lib/private/connector/sabre/filesplugin.php deleted file mode 100644 index 38a7139d9e9..00000000000 --- a/lib/private/connector/sabre/filesplugin.php +++ /dev/null @@ -1,265 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <rmccorkell@karoshi.org.uk> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use Sabre\DAV\IFile; -use \Sabre\DAV\PropFind; -use \Sabre\DAV\PropPatch; -use \Sabre\HTTP\RequestInterface; -use \Sabre\HTTP\ResponseInterface; - -class FilesPlugin extends \Sabre\DAV\ServerPlugin { - - // namespace - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id'; - const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}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'; - - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var \Sabre\DAV\Tree - */ - private $tree; - - /** - * Whether this is public webdav. - * If true, some returned information will be stripped off. - * - * @var bool - */ - private $isPublic; - - /** - * @var \OC\Files\View - */ - private $fileView; - - /** - * @param \Sabre\DAV\Tree $tree - * @param \OC\Files\View $view - * @param bool $isPublic - */ - public function __construct(\Sabre\DAV\Tree $tree, - \OC\Files\View $view, - $isPublic = false) { - $this->tree = $tree; - $this->fileView = $view; - $this->isPublic = $isPublic; - } - - /** - * 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->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; - $server->protectedProperties[] = self::FILEID_PROPERTYNAME; - $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME; - $server->protectedProperties[] = self::SIZE_PROPERTYNAME; - $server->protectedProperties[] = self::DOWNLOADURL_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('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 \Sabre\DAV\Exception\Forbidden - */ - function checkMove($source, $destination) { - list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source); - list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination); - - if ($sourceDir !== $destinationDir) { - $sourceFileInfo = $this->fileView->getFileInfo($source); - - if (!$sourceFileInfo->isDeletable()) { - throw new \Sabre\DAV\Exception\Forbidden($source . " cannot be deleted"); - } - } - } - - /** - * Plugin that adds a 'Content-Disposition: attachment' header to all files - * delivered by SabreDAV. - * @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; - - $response->addHeader('Content-Disposition', 'attachment'); - } - - /** - * Adds all ownCloud-specific properties - * - * @param PropFind $propFind - * @param \Sabre\DAV\INode $node - * @return void - */ - public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) { - - if ($node instanceof \OC\Connector\Sabre\Node) { - - $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) { - return $node->getFileId(); - }); - - $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::GETETAG_PROPERTYNAME, function() use ($node) { - return $node->getEtag(); - }); - } - - if ($node instanceof \OC\Connector\Sabre\File) { - $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) { - /** @var $node \OC\Connector\Sabre\File */ - $directDownloadUrl = $node->getDirectDownload(); - if (isset($directDownloadUrl['url'])) { - return $directDownloadUrl['url']; - } - return false; - }); - } - - if ($node instanceof \OC\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 \OC\Connector\Sabre\Node) { - $fileId = $node->getFileId(); - if (!is_null($fileId)) { - $this->server->httpResponse->setHeader('OC-FileId', $fileId); - } - } - } - -} diff --git a/lib/private/connector/sabre/listenerplugin.php b/lib/private/connector/sabre/listenerplugin.php deleted file mode 100644 index ec628add28b..00000000000 --- a/lib/private/connector/sabre/listenerplugin.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use OCP\AppFramework\Http; -use OCP\SabrePluginEvent; -use OCP\SabrePluginException; -use Sabre\DAV\ServerPlugin; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; - -class ListenerPlugin extends ServerPlugin { - /** @var EventDispatcherInterface */ - protected $dispatcher; - - /** - * @param EventDispatcherInterface $dispatcher - */ - public function __construct(EventDispatcherInterface $dispatcher) { - $this->dispatcher = $dispatcher; - } - - /** - * This initialize the plugin - * - * @param \Sabre\DAV\Server $server - */ - public function initialize(\Sabre\DAV\Server $server) { - $server->on('beforeMethod', array($this, 'emitListener'), 15); - } - - /** - * This method is called before any HTTP method and returns http status code 503 - * in case the system is in maintenance mode. - * - * @return bool - * @throws \Exception - */ - public function emitListener() { - $event = new SabrePluginEvent(); - - $this->dispatcher->dispatch('OC\Connector\Sabre::beforeMethod', $event); - - if ($event->getStatusCode() !== Http::STATUS_OK) { - throw new SabrePluginException($event->getMessage(), $event->getStatusCode()); - } - - return true; - } -} diff --git a/lib/private/connector/sabre/lockplugin.php b/lib/private/connector/sabre/lockplugin.php deleted file mode 100644 index a3a7bb84e39..00000000000 --- a/lib/private/connector/sabre/lockplugin.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use OC\Connector\Sabre\Exception\FileLocked; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; -use Sabre\DAV\Exception\NotFound; -use \Sabre\DAV\PropFind; -use \Sabre\DAV\PropPatch; -use Sabre\DAV\ServerPlugin; -use Sabre\DAV\Tree; -use Sabre\HTTP\RequestInterface; -use Sabre\HTTP\ResponseInterface; - -class LockPlugin extends ServerPlugin { - /** - * Reference to main server object - * - * @var \Sabre\DAV\Server - */ - private $server; - - /** - * @var \Sabre\DAV\Tree - */ - private $tree; - - /** - * @param \Sabre\DAV\Tree $tree tree - */ - public function __construct(Tree $tree) { - $this->tree = $tree; - } - - /** - * {@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 cant 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') { - return; - } - try { - $node = $this->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') { - return; - } - try { - $node = $this->tree->getNodeForPath($request->getPath()); - } catch (NotFound $e) { - return; - } - if ($node instanceof Node) { - $node->releaseLock(ILockingProvider::LOCK_SHARED); - } - } -} diff --git a/lib/private/connector/sabre/maintenanceplugin.php b/lib/private/connector/sabre/maintenanceplugin.php deleted file mode 100644 index 4b7ff8a39da..00000000000 --- a/lib/private/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) 2015, 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 OC\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/lib/private/connector/sabre/node.php b/lib/private/connector/sabre/node.php deleted file mode 100644 index 30faf9941bd..00000000000 --- a/lib/private/connector/sabre/node.php +++ /dev/null @@ -1,276 +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) 2015, 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 OC\Connector\Sabre; - -use OC\Connector\Sabre\Exception\InvalidPath; - - -abstract class Node implements \Sabre\DAV\INode { - /** - * Allow configuring the method used to generate Etags - * - * @var array(class_name, function_name) - */ - public static $ETagFunction = null; - - /** - * @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; - - /** - * Sets up the node, expects a full path name - * - * @param \OC\Files\View $view - * @param \OCP\Files\FileInfo $info - */ - public function __construct($view, $info) { - $this->fileView = $view; - $this->path = $this->fileView->getRelativePath($info->getPath()); - $this->info = $info; - } - - 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 int|float - */ - 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 string|null - */ - 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->isDeletable()) { - $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; - } - - 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/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php deleted file mode 100644 index 18d3c1dcf23..00000000000 --- a/lib/private/connector/sabre/objecttree.php +++ /dev/null @@ -1,284 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@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) 2015, 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 OC\Connector\Sabre; - -use OC\Connector\Sabre\Exception\InvalidPath; -use OC\Connector\Sabre\Exception\FileLocked; -use OC\Files\FileInfo; -use OC\Files\Mount\MoveableMount; -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; - } - - /** - * Returns the INode object for the requested path - * - * @param string $path - * @throws \Sabre\DAV\Exception\ServiceUnavailable - * @throws \Sabre\DAV\Exception\NotFound - * @return \Sabre\DAV\INode - */ - public function getNodeForPath($path) { - if (!$this->fileView) { - throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); - } - - $path = trim($path, '/'); - if ($path) { - try { - $this->fileView->verifyPath($path, basename($path)); - } catch (\OCP\Files\InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); - } - } - - if (isset($this->cache[$path])) { - return $this->cache[$path]; - } - - // 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) { - /** - * @var \OC\Files\Storage\Storage $storage - */ - $scanner = $storage->getScanner($internalPath); - // get data directly - $data = $scanner->getData($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 \OC\Connector\Sabre\Directory($this->fileView, $info); - } else { - $node = new \OC\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 . ', 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 (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 (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination); - $this->markDirty($destinationDir); - } -} diff --git a/lib/private/connector/sabre/principal.php b/lib/private/connector/sabre/principal.php deleted file mode 100644 index 9d81c4337d8..00000000000 --- a/lib/private/connector/sabre/principal.php +++ /dev/null @@ -1,205 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Felix Moeller <mail@felixmoeller.de> - * @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 Sebastian Döll <sebastian.doell@libasys.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use OCP\IUserManager; -use OCP\IConfig; -use \Sabre\DAV\PropPatch; - -class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface { - /** @var IConfig */ - private $config; - /** @var IUserManager */ - private $userManager; - - /** - * @param IConfig $config - * @param IUserManager $userManager - */ - public function __construct(IConfig $config, - IUserManager $userManager) { - $this->config = $config; - $this->userManager = $userManager; - } - - /** - * 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 === 'principals') { - foreach($this->userManager->search('') as $user) { - - $principal = [ - 'uri' => 'principals/' . $user->getUID(), - '{DAV:}displayname' => $user->getUID(), - ]; - - $email = $this->config->getUserValue($user->getUID(), 'settings', 'email'); - if(!empty($email)) { - $principal['{http://sabredav.org/ns}email-address'] = $email; - } - - $principals[] = $principal; - } - } - - 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) = explode('/', $path); - $user = $this->userManager->get($name); - - if ($prefix === 'principals' && !is_null($user)) { - $principal = [ - 'uri' => 'principals/' . $user->getUID(), - '{DAV:}displayname' => $user->getUID(), - ]; - - $email = $this->config->getUserValue($user->getUID(), 'settings', 'email'); - if($email) { - $principal['{http://sabredav.org/ns}email-address'] = $email; - } - - return $principal; - } - - return null; - } - - /** - * Returns the list of members for a group-principal - * - * @param string $principal - * @return string[] - * @throws \Sabre\DAV\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 \Sabre\DAV\Exception('Principal not found'); - } - - return [$principal['uri']]; - } - - /** - * Returns the list of groups a principal is a member of - * - * @param string $principal - * @return array - * @throws \Sabre\DAV\Exception - */ - public function getGroupMembership($principal) { - list($prefix, $name) = \Sabre\HTTP\URLUtil::splitPath($principal); - - $group_membership = array(); - if ($prefix === 'principals') { - $principal = $this->getPrincipalByPath($principal); - if (!$principal) { - throw new \Sabre\DAV\Exception('Principal not found'); - } - - // TODO: for now the user principal has only its own groups - return array( - 'principals/'.$name.'/calendar-proxy-read', - 'principals/'.$name.'/calendar-proxy-write', - // The addressbook groups are not supported in Sabre, - // see http://groups.google.com/group/sabredav-discuss/browse_thread/thread/ef2fa9759d55f8c#msg_5720afc11602e753 - //'principals/'.$name.'/addressbook-proxy-read', - //'principals/'.$name.'/addressbook-proxy-write', - ); - } - return $group_membership; - } - - /** - * 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 array $members - * @throws \Sabre\DAV\Exception - */ - public function setGroupMemberSet($principal, array $members) { - throw new \Sabre\DAV\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) { - return ''; - } -} diff --git a/lib/private/connector/sabre/quotaplugin.php b/lib/private/connector/sabre/quotaplugin.php deleted file mode 100644 index 22b687b3508..00000000000 --- a/lib/private/connector/sabre/quotaplugin.php +++ /dev/null @@ -1,141 +0,0 @@ -<?php -/** - * @author Felix Moeller <mail@felixmoeller.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <rmccorkell@karoshi.org.uk> - * @author scambra <sergio@entrecables.com> - * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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 = new \OC_FileChunking($info); - // subtract the already uploaded size to see whether - // there is still enough space for the remaining chunks - $length -= $chunkHandler->getCurrentSize(); - } - $freeSpace = $this->getFreeSpace($parentUri); - if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN && $length > $freeSpace) { - if (isset($chunkHandler)) { - $chunkHandler->cleanup(); - } - throw new \Sabre\DAV\Exception\InsufficientStorage(); - } - } - return true; - } - - 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 $parentUri - * @return mixed - */ - public function getFreeSpace($parentUri) { - try { - $freeSpace = $this->view->free_space($parentUri); - return $freeSpace; - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); - } - } -} diff --git a/lib/private/connector/sabre/server.php b/lib/private/connector/sabre/server.php deleted file mode 100644 index 7a031f1d32a..00000000000 --- a/lib/private/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) 2015, 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 OC\Connector\Sabre; - -/** - * Class \OC\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/lib/private/connector/sabre/serverfactory.php b/lib/private/connector/sabre/serverfactory.php deleted file mode 100644 index 893e29fd41c..00000000000 --- a/lib/private/connector/sabre/serverfactory.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use OCP\Files\Mount\IMountManager; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\ILogger; -use OCP\ITagManager; -use OCP\IUserSession; -use Sabre\DAV\Auth\Backend\BackendInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; - -class ServerFactory { - public function __construct( - IConfig $config, - ILogger $logger, - IDBConnection $databaseConnection, - IUserSession $userSession, - IMountManager $mountManager, - ITagManager $tagManager, - EventDispatcherInterface $dispatcher - ) { - $this->config = $config; - $this->logger = $logger; - $this->databaseConnection = $databaseConnection; - $this->userSession = $userSession; - $this->mountManager = $mountManager; - $this->tagManager = $tagManager; - $this->dispatcher = $dispatcher; - } - - /** - * @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 \OC\Connector\Sabre\ObjectTree(); - $server = new \OC\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 \OC\Connector\Sabre\MaintenancePlugin($this->config)); - $server->addPlugin(new \OC\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 \OC\Connector\Sabre\DummyGetResponsePlugin()); - $server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger)); - $server->addPlugin(new \OC\Connector\Sabre\LockPlugin($objectTree)); - $server->addPlugin(new \OC\Connector\Sabre\ListenerPlugin($this->dispatcher)); - - // wait with registering these until auth is handled and the filesystem is setup - $server->on('beforeMethod', function () use ($server, $objectTree, $viewCallBack) { - /** @var \OC\Files\View $view */ - $view = $viewCallBack(); - $rootInfo = $view->getFileInfo(''); - - // Create ownCloud Dir - if ($rootInfo->getType() === 'dir') { - $root = new \OC\Connector\Sabre\Directory($view, $rootInfo); - } else { - $root = new \OC\Connector\Sabre\File($view, $rootInfo); - } - $objectTree->init($root, $view, $this->mountManager); - - $server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree, $view)); - $server->addPlugin(new \OC\Connector\Sabre\QuotaPlugin($view)); - - if($this->userSession->isLoggedIn()) { - $server->addPlugin(new \OC\Connector\Sabre\TagsPlugin($objectTree, $this->tagManager)); - // custom properties plugin must be the last one - $server->addPlugin( - new \Sabre\DAV\PropertyStorage\Plugin( - new \OC\Connector\Sabre\CustomPropertiesBackend( - $objectTree, - $this->databaseConnection, - $this->userSession->getUser() - ) - ) - ); - } - $server->addPlugin(new \OC\Connector\Sabre\CopyEtagHeaderPlugin()); - }, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request - return $server; - } -} diff --git a/lib/private/connector/sabre/taglist.php b/lib/private/connector/sabre/taglist.php deleted file mode 100644 index 9fb34ba12d0..00000000000 --- a/lib/private/connector/sabre/taglist.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\Connector\Sabre; - -use Sabre\DAV; - -/** - * TagList property - * - * This property contains multiple "tag" elements, each containing a tag name. - */ -class TagList extends DAV\Property { - 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; - - } - - /** - * Serializes this property. - * - * @param DAV\Server $server - * @param \DOMElement $dom - * @return void - */ - public function serialize(DAV\Server $server,\DOMElement $dom) { - - $prefix = $server->xmlNamespaces[self::NS_OWNCLOUD]; - - foreach($this->tags as $tag) { - - $elem = $dom->ownerDocument->createElement($prefix . ':tag'); - $elem->appendChild($dom->ownerDocument->createTextNode($tag)); - - $dom->appendChild($elem); - } - - } - - /** - * Unserializes this property from a DOM Element - * - * This method returns an instance of this class. - * It will only decode tag values. - * - * @param \DOMElement $dom - * @param array $propertyMap - * @return \OC\Connector\Sabre\TagList - */ - static function unserialize(\DOMElement $dom, array $propertyMap) { - - $tags = array(); - foreach($dom->childNodes as $child) { - if (DAV\XMLUtil::toClarkNotation($child)==='{' . self::NS_OWNCLOUD . '}tag') { - $tags[] = $child->textContent; - } - } - return new self($tags); - - } - -} diff --git a/lib/private/connector/sabre/tagsplugin.php b/lib/private/connector/sabre/tagsplugin.php deleted file mode 100644 index 7756eb45bda..00000000000 --- a/lib/private/connector/sabre/tagsplugin.php +++ /dev/null @@ -1,292 +0,0 @@ -<?php -/** - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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 OC\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->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; - $server->propertyMap[self::TAGS_PROPERTYNAME] = 'OC\\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 \OC\Connector\Sabre\Node)) { - return; - } - - // need prefetch ? - if ($node instanceof \OC\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; - }); - } -} |