diff options
Diffstat (limited to 'apps/dav/lib')
-rw-r--r-- | apps/dav/lib/AppInfo/PluginManager.php | 170 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 5 | ||||
-rw-r--r-- | apps/dav/lib/CardDAV/CardDavBackend.php | 5 | ||||
-rw-r--r-- | apps/dav/lib/Command/CreateCalendar.php | 2 | ||||
-rw-r--r-- | apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php | 18 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Backend.php | 24 | ||||
-rw-r--r-- | apps/dav/lib/RootCollection.php | 19 | ||||
-rw-r--r-- | apps/dav/lib/Server.php | 16 |
8 files changed, 237 insertions, 22 deletions
diff --git a/apps/dav/lib/AppInfo/PluginManager.php b/apps/dav/lib/AppInfo/PluginManager.php new file mode 100644 index 00000000000..9cdf358c80e --- /dev/null +++ b/apps/dav/lib/AppInfo/PluginManager.php @@ -0,0 +1,170 @@ +<?php +/** + * @author Vincent Petry <pvince81@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud GmbH. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OCA\DAV\AppInfo; + +use OCP\App\IAppManager; +use OC\ServerContainer; +use OCP\AppFramework\QueryException; + +/** + * Manager for DAV plugins from apps, used to register them + * to the Sabre server. + */ +class PluginManager { + + /** + * @var ServerContainer + */ + private $container; + + /** + * @var IAppManager + */ + private $appManager; + + /** + * App plugins + * + * @var array + */ + private $plugins = null; + + /** + * App collections + * + * @var array + */ + private $collections = null; + + /** + * Contstruct a PluginManager + * + * @param ServerContainer $container server container for resolving plugin classes + * @param IAppManager $appManager app manager to loading apps and their info + */ + public function __construct(ServerContainer $container, IAppManager $appManager) { + $this->container = $container; + $this->appManager = $appManager; + } + + /** + * Returns an array of app-registered plugins + * + * @return array + */ + public function getAppPlugins() { + if (null === $this->plugins) { + $this->populate(); + } + return $this->plugins; + } + + /** + * Returns an array of app-registered collections + * + * @return array + */ + public function getAppCollections() { + if (null === $this->collections) { + $this->populate(); + } + return $this->collections; + } + + /** + * Retrieve plugin and collection list and populate attributes + */ + private function populate() { + $this->plugins = []; + $this->collections = []; + foreach ($this->appManager->getInstalledApps() as $app) { + // load plugins and collections from info.xml + $info = $this->appManager->getAppInfo($app); + if (!isset($info['types']) || !in_array('dav', $info['types'], true)) { + continue; + } + // FIXME: switch to public API once available + // load app to make sure its classes are available + \OC_App::loadApp($app); + $this->loadSabrePluginsFromInfoXml($this->extractPluginList($info)); + $this->loadSabreCollectionsFromInfoXml($this->extractCollectionList($info)); + } + } + + private function extractPluginList(array $array) { + if (isset($array['sabre']) && is_array($array['sabre'])) { + if (isset($array['sabre']['plugins']) && is_array($array['sabre']['plugins'])) { + if (isset($array['sabre']['plugins']['plugin'])) { + $items = $array['sabre']['plugins']['plugin']; + if (!is_array($items)) { + $items = [$items]; + } + return $items; + } + } + } + return []; + } + + private function extractCollectionList(array $array) { + if (isset($array['sabre']) && is_array($array['sabre'])) { + if (isset($array['sabre']['collections']) && is_array($array['sabre']['collections'])) { + if (isset($array['sabre']['collections']['collection'])) { + $items = $array['sabre']['collections']['collection']; + if (!is_array($items)) { + $items = [$items]; + } + return $items; + } + } + } + return []; + } + + private function loadSabrePluginsFromInfoXml(array $plugins) { + foreach ($plugins as $plugin) { + try { + $this->plugins[] = $this->container->query($plugin); + } catch (QueryException $e) { + if (class_exists($plugin)) { + $this->plugins[] = new $plugin(); + } else { + throw new \Exception("Sabre plugin class '$plugin' is unknown and could not be loaded"); + } + } + } + } + + private function loadSabreCollectionsFromInfoXml(array $collections) { + foreach ($collections as $collection) { + try { + $this->collections[] = $this->container->query($collection); + } catch (QueryException $e) { + if (class_exists($collection)) { + $this->collections[] = new $collection(); + } else { + throw new \Exception("Sabre collection class '$collection' is unknown and could not be loaded"); + } + } + } + } + +} diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 83ef06f29e1..2c34f6d6d31 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -32,6 +32,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\DAV\Sharing\Backend; use OCP\IDBConnection; +use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; use OCP\Security\ISecureRandom; @@ -158,6 +159,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription * @param IDBConnection $db * @param Principal $principalBackend * @param IUserManager $userManager + * @param IGroupManager $groupManager * @param ISecureRandom $random * @param EventDispatcherInterface $dispatcher * @param bool $legacyEndpoint @@ -165,13 +167,14 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription public function __construct(IDBConnection $db, Principal $principalBackend, IUserManager $userManager, + IGroupManager $groupManager, ISecureRandom $random, EventDispatcherInterface $dispatcher, $legacyEndpoint = false) { $this->db = $db; $this->principalBackend = $principalBackend; $this->userManager = $userManager; - $this->sharingBackend = new Backend($this->db, $principalBackend, 'calendar'); + $this->sharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'calendar'); $this->random = $random; $this->dispatcher = $dispatcher; $this->legacyEndpoint = $legacyEndpoint; diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index 2e4acad6dfe..7c73a2cb941 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -33,6 +33,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCA\DAV\DAV\Sharing\Backend; use OCA\DAV\DAV\Sharing\IShareable; use OCP\IDBConnection; +use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; use PDO; @@ -88,17 +89,19 @@ class CardDavBackend implements BackendInterface, SyncSupport { * @param IDBConnection $db * @param Principal $principalBackend * @param IUserManager $userManager + * @param IGroupManager $groupManager * @param EventDispatcherInterface $dispatcher */ public function __construct(IDBConnection $db, Principal $principalBackend, IUserManager $userManager, + IGroupManager $groupManager, EventDispatcherInterface $dispatcher) { $this->db = $db; $this->principalBackend = $principalBackend; $this->userManager = $userManager; $this->dispatcher = $dispatcher; - $this->sharingBackend = new Backend($this->db, $principalBackend, 'addressbook'); + $this->sharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'addressbook'); } /** diff --git a/apps/dav/lib/Command/CreateCalendar.php b/apps/dav/lib/Command/CreateCalendar.php index 24990352fab..adc86faa190 100644 --- a/apps/dav/lib/Command/CreateCalendar.php +++ b/apps/dav/lib/Command/CreateCalendar.php @@ -79,7 +79,7 @@ class CreateCalendar extends Command { $dispatcher = \OC::$server->getEventDispatcher(); $name = $input->getArgument('name'); - $caldav = new CalDavBackend($this->dbConnection, $principalBackend, $this->userManager, $random, $dispatcher); + $caldav = new CalDavBackend($this->dbConnection, $principalBackend, $this->userManager, $this->groupManager, $random, $dispatcher); $caldav->createCalendar("principals/users/$user", $name, []); } } diff --git a/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php b/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php index ca2195fc65a..ba7ea13c548 100644 --- a/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php +++ b/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php @@ -27,28 +27,34 @@ namespace OCA\DAV\Connector\Sabre; +use OCA\DAV\Connector\Sabre\Exception\PasswordLoginForbidden; +use OCP\Files\StorageNotAvailableException; use OCP\ILogger; +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotAuthenticated; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\PreconditionFailed; use Sabre\DAV\Exception\ServiceUnavailable; class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin { protected $nonFatalExceptions = [ - 'Sabre\DAV\Exception\NotAuthenticated' => true, + NotAuthenticated::class => true, // If tokenauth can throw this exception (which is basically as // NotAuthenticated. So not fatal. - 'OCA\DAV\Connector\Sabre\Exception\PasswordLoginForbidden' => true, + PasswordLoginForbidden::class => 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, + NotFound::class => 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, + PreconditionFailed::class => true, // forbidden can be expected when trying to upload to // read-only folders for example - 'Sabre\DAV\Exception\Forbidden' => true, + Forbidden::class => true, // Happens when an external storage or federated share is temporarily // not available - 'Sabre\DAV\Exception\StorageNotAvailableException' => true, + StorageNotAvailableException::class => true, ]; /** @var string */ diff --git a/apps/dav/lib/DAV/Sharing/Backend.php b/apps/dav/lib/DAV/Sharing/Backend.php index 6cc5e3b6f50..aa4b137f2b0 100644 --- a/apps/dav/lib/DAV/Sharing/Backend.php +++ b/apps/dav/lib/DAV/Sharing/Backend.php @@ -26,11 +26,17 @@ namespace OCA\DAV\DAV\Sharing; use OCA\DAV\Connector\Sabre\Principal; use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUserManager; class Backend { /** @var IDBConnection */ private $db; + /** @var IUserManager */ + private $userManager; + /** @var IGroupManager */ + private $groupManager; /** @var Principal */ private $principalBackend; /** @var string */ @@ -42,11 +48,15 @@ class Backend { /** * @param IDBConnection $db + * @param IUserManager $userManager + * @param IGroupManager $groupManager * @param Principal $principalBackend * @param string $resourceType */ - public function __construct(IDBConnection $db, Principal $principalBackend, $resourceType) { + public function __construct(IDBConnection $db, IUserManager $userManager, IGroupManager $groupManager, Principal $principalBackend, $resourceType) { $this->db = $db; + $this->userManager = $userManager; + $this->groupManager = $groupManager; $this->principalBackend = $principalBackend; $this->resourceType = $resourceType; } @@ -81,6 +91,18 @@ class Backend { return; } + $principal = explode('/', $parts[1], 3); + if (count($principal) !== 3 || $principal[0] !== 'principals' || !in_array($principal[1], ['users', 'groups'], true)) { + // Invalid principal + return; + } + + if (($principal[1] === 'users' && !$this->userManager->userExists($principal[2])) || + ($principal[1] === 'groups' && !$this->groupManager->groupExists($principal[2]))) { + // User or group does not exist + return; + } + // remove the share if it already exists $this->unshare($shareable, $element['href']); $access = self::ACCESS_READ; diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index a243ec6d00a..e4ba1f2c02a 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -41,15 +41,14 @@ class RootCollection extends SimpleCollection { $config = \OC::$server->getConfig(); $random = \OC::$server->getSecureRandom(); $userManager = \OC::$server->getUserManager(); + $groupManager = \OC::$server->getGroupManager(); $db = \OC::$server->getDatabaseConnection(); $dispatcher = \OC::$server->getEventDispatcher(); $userPrincipalBackend = new Principal( $userManager, - \OC::$server->getGroupManager() - ); - $groupPrincipalBackend = new GroupPrincipalBackend( - \OC::$server->getGroupManager() + $groupManager ); + $groupPrincipalBackend = new GroupPrincipalBackend($groupManager); // as soon as debug mode is enabled we allow listing of principals $disableListing = !$config->getSystemValue('debug', false); @@ -62,7 +61,7 @@ class RootCollection extends SimpleCollection { $systemPrincipals->disableListing = $disableListing; $filesCollection = new Files\RootCollection($userPrincipalBackend, 'principals/users'); $filesCollection->disableListing = $disableListing; - $caldavBackend = new CalDavBackend($db, $userPrincipalBackend, $userManager, $random, $dispatcher); + $caldavBackend = new CalDavBackend($db, $userPrincipalBackend, $userManager, $groupManager, $random, $dispatcher); $calendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; $publicCalendarRoot = new PublicCalendarRoot($caldavBackend); @@ -71,28 +70,28 @@ class RootCollection extends SimpleCollection { $systemTagCollection = new SystemTag\SystemTagsByIdCollection( \OC::$server->getSystemTagManager(), \OC::$server->getUserSession(), - \OC::$server->getGroupManager() + $groupManager ); $systemTagRelationsCollection = new SystemTag\SystemTagsRelationsCollection( \OC::$server->getSystemTagManager(), \OC::$server->getSystemTagObjectMapper(), \OC::$server->getUserSession(), - \OC::$server->getGroupManager(), + $groupManager, \OC::$server->getEventDispatcher() ); $commentsCollection = new Comments\RootCollection( \OC::$server->getCommentsManager(), - \OC::$server->getUserManager(), + $userManager, \OC::$server->getUserSession(), \OC::$server->getEventDispatcher(), \OC::$server->getLogger() ); - $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, \OC::$server->getUserManager(), $dispatcher); + $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $userManager, $groupManager, $dispatcher); $usersAddressBookRoot = new AddressBookRoot($userPrincipalBackend, $usersCardDavBackend, 'principals/users'); $usersAddressBookRoot->disableListing = $disableListing; - $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, \OC::$server->getUserManager(), $dispatcher); + $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $userManager, $groupManager, $dispatcher); $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system'); $systemAddressBookRoot->disableListing = $disableListing; diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index bfb67e2e5fe..719e4974755 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -55,8 +55,8 @@ use OCP\SabrePluginEvent; use Sabre\CardDAV\VCFExportPlugin; use Sabre\DAV\Auth\Plugin; use OCA\DAV\Connector\Sabre\TagsPlugin; -use Sabre\HTTP\Auth\Bearer; use SearchDAV\DAV\SearchPlugin; +use OCA\DAV\AppInfo\PluginManager; class Server { @@ -187,7 +187,7 @@ class Server { } // wait with registering these until auth is handled and the filesystem is setup - $this->server->on('beforeMethod', function () { + $this->server->on('beforeMethod', function () use ($root) { // custom properties plugin must be the last one $userSession = \OC::$server->getUserSession(); $user = $userSession->getUser(); @@ -255,6 +255,18 @@ class Server { ))); } } + + // register plugins from apps + $pluginManager = new PluginManager( + \OC::$server, + \OC::$server->getAppManager() + ); + foreach ($pluginManager->getAppPlugins() as $appPlugin) { + $this->server->addPlugin($appPlugin); + } + foreach ($pluginManager->getAppCollections() as $appCollection) { + $root->addChild($appCollection); + } }); } |