ServerFactory.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\DAV\Connector\Sabre;
  8. use OC\Files\View;
  9. use OCA\DAV\AppInfo\PluginManager;
  10. use OCA\DAV\CalDAV\DefaultCalendarValidator;
  11. use OCA\DAV\DAV\CustomPropertiesBackend;
  12. use OCA\DAV\DAV\ViewOnlyPlugin;
  13. use OCA\DAV\Files\BrowserErrorPagePlugin;
  14. use OCA\Theming\ThemingDefaults;
  15. use OCP\EventDispatcher\IEventDispatcher;
  16. use OCP\Files\Folder;
  17. use OCP\Files\IFilenameValidator;
  18. use OCP\Files\Mount\IMountManager;
  19. use OCP\IConfig;
  20. use OCP\IDBConnection;
  21. use OCP\IL10N;
  22. use OCP\IPreview;
  23. use OCP\IRequest;
  24. use OCP\ITagManager;
  25. use OCP\IUserSession;
  26. use OCP\SabrePluginEvent;
  27. use Psr\Log\LoggerInterface;
  28. use Sabre\DAV\Auth\Plugin;
  29. class ServerFactory {
  30. public function __construct(
  31. private IConfig $config,
  32. private LoggerInterface $logger,
  33. private IDBConnection $databaseConnection,
  34. private IUserSession $userSession,
  35. private IMountManager $mountManager,
  36. private ITagManager $tagManager,
  37. private IRequest $request,
  38. private IPreview $previewManager,
  39. private IEventDispatcher $eventDispatcher,
  40. private IL10N $l10n,
  41. ) {
  42. }
  43. /**
  44. * @param callable $viewCallBack callback that should return the view for the dav endpoint
  45. */
  46. public function createServer(string $baseUri,
  47. string $requestUri,
  48. Plugin $authPlugin,
  49. callable $viewCallBack): Server {
  50. // Fire up server
  51. $objectTree = new ObjectTree();
  52. $server = new Server($objectTree);
  53. // Set URL explicitly due to reverse-proxy situations
  54. $server->httpRequest->setUrl($requestUri);
  55. $server->setBaseUri($baseUri);
  56. // Load plugins
  57. $server->addPlugin(new MaintenancePlugin($this->config, $this->l10n));
  58. $server->addPlugin(new BlockLegacyClientPlugin(
  59. $this->config,
  60. \OCP\Server::get(ThemingDefaults::class),
  61. ));
  62. $server->addPlugin(new AnonymousOptionsPlugin());
  63. $server->addPlugin($authPlugin);
  64. // FIXME: The following line is a workaround for legacy components relying on being able to send a GET to /
  65. $server->addPlugin(new DummyGetResponsePlugin());
  66. $server->addPlugin(new ExceptionLoggerPlugin('webdav', $this->logger));
  67. $server->addPlugin(new LockPlugin());
  68. $server->addPlugin(new RequestIdHeaderPlugin($this->request));
  69. $server->addPlugin(new ZipFolderPlugin(
  70. $objectTree,
  71. $this->logger,
  72. $this->eventDispatcher,
  73. ));
  74. // Some WebDAV clients do require Class 2 WebDAV support (locking), since
  75. // we do not provide locking we emulate it using a fake locking plugin.
  76. if ($this->request->isUserAgent([
  77. '/WebDAVFS/',
  78. '/OneNote/',
  79. '/Microsoft-WebDAV-MiniRedir/',
  80. ])) {
  81. $server->addPlugin(new FakeLockerPlugin());
  82. }
  83. if (BrowserErrorPagePlugin::isBrowserRequest($this->request)) {
  84. $server->addPlugin(new BrowserErrorPagePlugin());
  85. }
  86. // wait with registering these until auth is handled and the filesystem is setup
  87. $server->on('beforeMethod:*', function () use ($server, $objectTree, $viewCallBack): void {
  88. // ensure the skeleton is copied
  89. $userFolder = \OC::$server->getUserFolder();
  90. /** @var View $view */
  91. $view = $viewCallBack($server);
  92. if ($userFolder instanceof Folder && $userFolder->getPath() === $view->getRoot()) {
  93. $rootInfo = $userFolder;
  94. } else {
  95. $rootInfo = $view->getFileInfo('');
  96. }
  97. // Create Nextcloud Dir
  98. if ($rootInfo->getType() === 'dir') {
  99. $root = new Directory($view, $rootInfo, $objectTree);
  100. } else {
  101. $root = new File($view, $rootInfo);
  102. }
  103. $objectTree->init($root, $view, $this->mountManager);
  104. $server->addPlugin(
  105. new FilesPlugin(
  106. $objectTree,
  107. $this->config,
  108. $this->request,
  109. $this->previewManager,
  110. $this->userSession,
  111. \OCP\Server::get(IFilenameValidator::class),
  112. false,
  113. !$this->config->getSystemValue('debug', false)
  114. )
  115. );
  116. $server->addPlugin(new QuotaPlugin($view, true));
  117. $server->addPlugin(new ChecksumUpdatePlugin());
  118. // Allow view-only plugin for webdav requests
  119. $server->addPlugin(new ViewOnlyPlugin(
  120. $userFolder,
  121. ));
  122. if ($this->userSession->isLoggedIn()) {
  123. $server->addPlugin(new TagsPlugin($objectTree, $this->tagManager, $this->eventDispatcher, $this->userSession));
  124. $server->addPlugin(new SharesPlugin(
  125. $objectTree,
  126. $this->userSession,
  127. $userFolder,
  128. \OC::$server->getShareManager()
  129. ));
  130. $server->addPlugin(new CommentPropertiesPlugin(\OC::$server->getCommentsManager(), $this->userSession));
  131. $server->addPlugin(new FilesReportPlugin(
  132. $objectTree,
  133. $view,
  134. \OC::$server->getSystemTagManager(),
  135. \OC::$server->getSystemTagObjectMapper(),
  136. \OC::$server->getTagManager(),
  137. $this->userSession,
  138. \OC::$server->getGroupManager(),
  139. $userFolder,
  140. \OC::$server->getAppManager()
  141. ));
  142. // custom properties plugin must be the last one
  143. $server->addPlugin(
  144. new \Sabre\DAV\PropertyStorage\Plugin(
  145. new CustomPropertiesBackend(
  146. $server,
  147. $objectTree,
  148. $this->databaseConnection,
  149. $this->userSession->getUser(),
  150. \OC::$server->get(DefaultCalendarValidator::class),
  151. )
  152. )
  153. );
  154. }
  155. $server->addPlugin(new CopyEtagHeaderPlugin());
  156. // Load dav plugins from apps
  157. $event = new SabrePluginEvent($server);
  158. $this->eventDispatcher->dispatchTyped($event);
  159. $pluginManager = new PluginManager(
  160. \OC::$server,
  161. \OC::$server->getAppManager()
  162. );
  163. foreach ($pluginManager->getAppPlugins() as $appPlugin) {
  164. $server->addPlugin($appPlugin);
  165. }
  166. }, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request
  167. return $server;
  168. }
  169. }