FakeLockerPlugin.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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 Sabre\DAV\INode;
  9. use Sabre\DAV\Locks\LockInfo;
  10. use Sabre\DAV\PropFind;
  11. use Sabre\DAV\ServerPlugin;
  12. use Sabre\DAV\Xml\Property\LockDiscovery;
  13. use Sabre\DAV\Xml\Property\SupportedLock;
  14. use Sabre\HTTP\RequestInterface;
  15. use Sabre\HTTP\ResponseInterface;
  16. /**
  17. * Class FakeLockerPlugin is a plugin only used when connections come in from
  18. * OS X via Finder. The fake locking plugin does emulate Class 2 WebDAV support
  19. * (locking of files) which allows Finder to access the storage in write mode as
  20. * well.
  21. *
  22. * No real locking is performed, instead the plugin just returns always positive
  23. * responses.
  24. *
  25. * @see https://github.com/owncloud/core/issues/17732
  26. * @package OCA\DAV\Connector\Sabre
  27. */
  28. class FakeLockerPlugin extends ServerPlugin {
  29. /** @var \Sabre\DAV\Server */
  30. private $server;
  31. /** {@inheritDoc} */
  32. public function initialize(\Sabre\DAV\Server $server) {
  33. $this->server = $server;
  34. $this->server->on('method:LOCK', [$this, 'fakeLockProvider'], 1);
  35. $this->server->on('method:UNLOCK', [$this, 'fakeUnlockProvider'], 1);
  36. $server->on('propFind', [$this, 'propFind']);
  37. $server->on('validateTokens', [$this, 'validateTokens']);
  38. }
  39. /**
  40. * Indicate that we support LOCK and UNLOCK
  41. *
  42. * @param string $path
  43. * @return string[]
  44. */
  45. public function getHTTPMethods($path) {
  46. return [
  47. 'LOCK',
  48. 'UNLOCK',
  49. ];
  50. }
  51. /**
  52. * Indicate that we support locking
  53. *
  54. * @return integer[]
  55. */
  56. public function getFeatures() {
  57. return [2];
  58. }
  59. /**
  60. * Return some dummy response for PROPFIND requests with regard to locking
  61. *
  62. * @param PropFind $propFind
  63. * @param INode $node
  64. * @return void
  65. */
  66. public function propFind(PropFind $propFind, INode $node) {
  67. $propFind->handle('{DAV:}supportedlock', function () {
  68. return new SupportedLock();
  69. });
  70. $propFind->handle('{DAV:}lockdiscovery', function () use ($propFind) {
  71. return new LockDiscovery([]);
  72. });
  73. }
  74. /**
  75. * Mark a locking token always as valid
  76. *
  77. * @param RequestInterface $request
  78. * @param array $conditions
  79. */
  80. public function validateTokens(RequestInterface $request, &$conditions) {
  81. foreach ($conditions as &$fileCondition) {
  82. if (isset($fileCondition['tokens'])) {
  83. foreach ($fileCondition['tokens'] as &$token) {
  84. if (isset($token['token'])) {
  85. if (str_starts_with($token['token'], 'opaquelocktoken:')) {
  86. $token['validToken'] = true;
  87. }
  88. }
  89. }
  90. }
  91. }
  92. }
  93. /**
  94. * Fakes a successful LOCK
  95. *
  96. * @param RequestInterface $request
  97. * @param ResponseInterface $response
  98. * @return bool
  99. */
  100. public function fakeLockProvider(RequestInterface $request,
  101. ResponseInterface $response) {
  102. $lockInfo = new LockInfo();
  103. $lockInfo->token = md5($request->getPath());
  104. $lockInfo->uri = $request->getPath();
  105. $lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
  106. $lockInfo->timeout = 1800;
  107. $body = $this->server->xml->write('{DAV:}prop', [
  108. '{DAV:}lockdiscovery' =>
  109. new LockDiscovery([$lockInfo])
  110. ]);
  111. $response->setStatus(200);
  112. $response->setBody($body);
  113. return false;
  114. }
  115. /**
  116. * Fakes a successful LOCK
  117. *
  118. * @param RequestInterface $request
  119. * @param ResponseInterface $response
  120. * @return bool
  121. */
  122. public function fakeUnlockProvider(RequestInterface $request,
  123. ResponseInterface $response) {
  124. $response->setStatus(204);
  125. $response->setHeader('Content-Length', '0');
  126. return false;
  127. }
  128. }