PNG  IHDR;IDATxܻn0K )(pA 7LeG{ §㻢|ذaÆ 6lذaÆ 6lذaÆ 6lom$^yذag5bÆ 6lذaÆ 6lذa{ 6lذaÆ `}HFkm,mӪôô! x|'ܢ˟;E:9&ᶒ}{v]n&6 h_tڠ͵-ҫZ;Z$.Pkž)!o>}leQfJTu іچ\X=8Rن4`Vwl>nG^is"ms$ui?wbs[m6K4O.4%/bC%t Mז -lG6mrz2s%9s@-k9=)kB5\+͂Zsٲ Rn~GRC wIcIn7jJhۛNCS|j08yiHKֶۛkɈ+;SzL/F*\Ԕ#"5m2[S=gnaPeғL lذaÆ 6l^ḵaÆ 6lذaÆ 6lذa; _ذaÆ 6lذaÆ 6lذaÆ RIENDB` * @author Georg Ehrke * @author Lukas Reschke * @author Roeland Jago Douma * @author Thomas Citharel * @author Thomas Müller * @author Vincent Petry * * @copyright Copyright (c) 2018, 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 * */ namespace OCA\DAV; use OC; use OC\Files\Filesystem; use OCA\DAV\AppInfo\PluginManager; use OCA\DAV\CalDAV\Publishing\PublishPlugin; use OCA\DAV\CalDAV\Schedule\IMipPlugin; use OCA\DAV\CardDAV\ImageExportPlugin; use OCA\DAV\Connector\Sabre\Auth; use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin; use OCA\DAV\Connector\Sabre\CommentPropertiesPlugin; use OCA\DAV\Connector\Sabre\CopyEtagHeaderPlugin; use OCA\DAV\Connector\Sabre\CorsPlugin; use OCA\DAV\Connector\Sabre\DavAclPlugin; use OCA\DAV\Connector\Sabre\DummyGetResponsePlugin; use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin; use OCA\DAV\Connector\Sabre\FilesPlugin; use OCA\DAV\Connector\Sabre\FilesReportPlugin; use OCA\DAV\Connector\Sabre\FilesSearchReportPlugin; use OCA\DAV\Connector\Sabre\LockPlugin; use OCA\DAV\Connector\Sabre\MaintenancePlugin; use OCA\DAV\Connector\Sabre\QuotaPlugin; use OCA\DAV\Connector\Sabre\SharesPlugin; use OCA\DAV\Connector\Sabre\TagsPlugin; use OCA\DAV\Connector\Sabre\ValidateRequestPlugin; use OCA\DAV\DAV\FileCustomPropertiesBackend; use OCA\DAV\DAV\FileCustomPropertiesPlugin; use OCA\DAV\DAV\LazyOpsPlugin; use OCA\DAV\DAV\MiscCustomPropertiesBackend; use OCA\DAV\DAV\PublicAuth; use OCA\DAV\DAV\ViewOnlyPlugin; use OCA\DAV\Files\BrowserErrorPagePlugin; use OCA\DAV\Files\FileLocksBackend; use OCA\DAV\Files\PreviewPlugin; use OCA\DAV\Files\PublicFiles\PublicFilesPlugin; use OCA\DAV\Files\Sharing\PublicLinkEventsPlugin; use OCA\DAV\JobStatus\Entity\JobStatusMapper; use OCA\DAV\Meta\MetaPlugin; use OCA\DAV\Files\PublicFiles\PublicSharingAuth; use OCA\DAV\SystemTag\SystemTagPlugin; use OCA\DAV\TrashBin\TrashBinPlugin; use OCA\DAV\Upload\ChunkingPlugin; use OCP\AppFramework\QueryException; use OCP\IRequest; use OCP\SabrePluginEvent; use Sabre\CalDAV\ICSExportPlugin; use Sabre\CardDAV\VCFExportPlugin; use Sabre\DAV\Auth\Plugin; use Sabre\DAV\Exception; use Sabre\HTTP\Request; class Server { /** @var Connector\Sabre\Server */ public $server; /** @var string */ private $baseUri; /** @var IRequest */ private $request; /** * Server constructor. * * @param IRequest $request * @param string $baseUri * @throws QueryException * @throws Exception */ public function __construct(IRequest $request, $baseUri) { $this->request = $request; $this->baseUri = $baseUri; $logger = OC::$server->getLogger(); $dispatcher = OC::$server->getEventDispatcher(); $root = new RootCollection(); $tree = new Tree($root); $this->server = new Connector\Sabre\Server($tree); $config = OC::$server->getConfig(); if ($config->getSystemValue('dav.enable.async', false)) { $this->server->addPlugin(new LazyOpsPlugin( OC::$server->getUserSession(), OC::$server->getURLGenerator(), OC::$server->getShutdownHandler(), OC::$server->query(JobStatusMapper::class), OC::$server->getLogger() )); } // Backends $authBackend = new Auth( OC::$server->getSession(), OC::$server->getUserSession(), OC::$server->getRequest(), OC::$server->getTwoFactorAuthManager(), OC::$server->getAccountModuleManager(), \OC::$server->getConfig() ); // Set URL explicitly due to reverse-proxy situations $this->server->httpRequest->setUrl($this->request->getRequestUri()); $this->server->setBaseUri($this->baseUri); $this->server->addPlugin(new MaintenancePlugin($config)); $this->server->addPlugin(new ValidateRequestPlugin('dav')); $this->server->addPlugin(new BlockLegacyClientPlugin($config)); $this->server->addPlugin(new CorsPlugin(OC::$server->getUserSession())); $authPlugin = new Plugin(); $isPublicAccess = false; if ($this->isRequestForSubtree(['public-files']) ) { $this->server->addPlugin(new PublicFilesPlugin()); $authPlugin->addBackend(new PublicSharingAuth($this->server, OC::$server->getShareManager())); $this->server->addPlugin(new PublicLinkEventsPlugin(\OC::$server->getEventDispatcher())); $isPublicAccess = true; } $authPlugin->addBackend(new PublicAuth()); $this->server->addPlugin($authPlugin); // allow setup of additional auth backends $event = new SabrePluginEvent($this->server); $dispatcher->dispatch($event, 'OCA\DAV\Connector\Sabre::authInit'); // because we are throwing exceptions this plugin has to be the last one $authPlugin->addBackend($authBackend); // debugging if (OC::$server->getConfig()->getSystemValue('debug', false)) { $this->server->addPlugin(new \Sabre\DAV\Browser\Plugin()); } else { $this->server->addPlugin(new DummyGetResponsePlugin()); } $this->server->addPlugin(new ExceptionLoggerPlugin('webdav', $logger)); $this->server->addPlugin(new \Sabre\DAV\Sync\Plugin()); $this->server->addPlugin(new LockPlugin(\OC::$server->getConfig(), \OC::$server->getGroupManager())); $fileLocksBackend = new FileLocksBackend($this->server->tree, false, OC::$server->getTimeFactory(), $isPublicAccess); $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\PublicDavLocksPlugin($fileLocksBackend, function ($uri) { if (\strpos($uri, "public-files/") === 0) { return true; } return false; })); // ACL plugin not used in files subtree, also it causes issues // with performance and locking issues because it will query // every parent node which might trigger an implicit rescan in the // case of external storages with update detection if (!$this->isRequestForSubtree(['files'])) { // acl $acl = new DavAclPlugin(); $acl->principalCollectionSet = [ 'principals/users', 'principals/groups' ]; $acl->defaultUsernamePath = 'principals/users'; $this->server->addPlugin($acl); } // calendar plugins if ($this->isRequestForSubtree(['calendars', 'public-calendars', 'principals'])) { $mailer = OC::$server->getMailer(); $this->server->addPlugin(new CalDAV\Plugin()); $this->server->addPlugin(new ICSExportPlugin()); $this->server->addPlugin(new CalDAV\Schedule\Plugin()); $this->server->addPlugin(new IMipPlugin($mailer, $logger, $request)); $this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin()); $this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin()); $this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, OC::$server->getRequest())); $this->server->addPlugin(new PublishPlugin( OC::$server->getConfig(), OC::$server->getURLGenerator() )); } // addressbook plugins if ($this->isRequestForSubtree(['addressbooks', 'principals'])) { $this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, OC::$server->getRequest())); $this->server->addPlugin(new CardDAV\Plugin()); $this->server->addPlugin(new VCFExportPlugin()); $this->server->addPlugin(new ImageExportPlugin(OC::$server->getLogger())); } // system tags plugins $this->server->addPlugin(new SystemTagPlugin( OC::$server->getSystemTagManager(), OC::$server->getGroupManager(), OC::$server->getUserSession() )); $this->server->addPlugin(new CopyEtagHeaderPlugin()); $this->server->addPlugin(new ChunkingPlugin()); $this->server->addPlugin(new TrashBinPlugin()); $this->server->addPlugin(new MetaPlugin( OC::$server->getUserSession(), OC::$server->getLazyRootFolder() )); // enable streaming only for the files subtree if ($this->isRequestForSubtree(['files'])) { \Sabre\DAV\Server::$streamMultiStatus = true; } if ($this->isRequestForSubtree(['files', 'meta', 'trash-bin', 'public-files'])) { $this->server->addPlugin(new ViewOnlyPlugin( OC::$server->getLogger() )); } if (BrowserErrorPagePlugin::isBrowserRequest($request)) { $this->server->addPlugin(new BrowserErrorPagePlugin()); } $this->server->addPlugin(new PreviewPlugin(OC::$server->getTimeFactory(), OC::$server->getPreviewManager())); $this->server->on('beforeMethod:PROPFIND', function (Request $request) use ($config) { $depthHeader = strtolower($request->getHeader('depth')); if ($depthHeader === 'infinity' && !$config->getSystemValue('dav.propfind.depth_infinity', false)) { throw new Exception\PreconditionFailed('Depth infinity not supported'); } }, 0); // wait with registering these until auth is handled and the filesystem is setup $this->server->on('beforeMethod:*', function () use ($root) { // custom properties plugin must be the last one $userSession = OC::$server->getUserSession(); $user = $userSession->getUser(); if ($user !== null) { $view = Filesystem::getView(); $this->server->addPlugin( new FilesPlugin( $this->server->tree, OC::$server->getConfig(), $this->request, false, !OC::$server->getConfig()->getSystemValue('debug', false) ) ); if ($this->isRequestForSubtree(['files', 'uploads', 'trash-bin', 'public-files'])) { //For files only $filePropertiesPlugin = new FileCustomPropertiesPlugin( new FileCustomPropertiesBackend( $this->server->tree, OC::$server->getDatabaseConnection(), OC::$server->getUserSession()->getUser(), OC::$server->getRootFolder() ) ); $this->server->addPlugin($filePropertiesPlugin); } else { $miscPropertiesPlugin = new \Sabre\DAV\PropertyStorage\Plugin( new MiscCustomPropertiesBackend( $this->server->tree, OC::$server->getDatabaseConnection(), OC::$server->getUserSession()->getUser(), OC::$server->getRootFolder() ) ); $this->server->addPlugin($miscPropertiesPlugin); } if ($view !== null) { $this->server->addPlugin( new QuotaPlugin($view) ); } $this->server->addPlugin( new TagsPlugin( $this->server->tree, OC::$server->getTagManager() ) ); // TODO: switch to LazyUserFolder $userFolder = OC::$server->getUserFolder(); $this->server->addPlugin(new SharesPlugin( $this->server->tree, $userSession, OC::$server->getShareManager() )); $this->server->addPlugin(new CommentPropertiesPlugin( OC::$server->getCommentsManager(), $userSession )); if ($view !== null) { $this->server->addPlugin(new FilesReportPlugin( $this->server->tree, $view, OC::$server->getSystemTagManager(), OC::$server->getSystemTagObjectMapper(), OC::$server->getTagManager(), $userSession, OC::$server->getGroupManager(), $userFolder )); } $this->server->addPlugin( new FilesSearchReportPlugin( OC::$server->getSearch() ) ); } // 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); } }); } public function exec() { $this->server->start(); } /** * @param string[] $subTrees * @return bool */ private function isRequestForSubtree(array $subTrees) { foreach ($subTrees as $subTree) { $subTree = \trim($subTree, ' /'); if (\strpos($this->server->getRequestUri(), "$subTree/") === 0) { return true; } } return false; } }