[Pkg-owncloud-commits] [owncloud] 02/107: [stable8.2] Add fake locker plugin

David Prévot taffit at moszumanska.debian.org
Thu Dec 17 19:40:29 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch stable8
in repository owncloud.

commit 5641e4c103c9fb446a221576dd91f1ba2b8d8453
Author: Lukas Reschke <lukas at owncloud.com>
Date:   Mon Nov 16 15:03:59 2015 +0100

    [stable8.2] Add fake locker plugin
---
 apps/files/appinfo/remote.php                      |   3 +-
 apps/files_sharing/publicwebdav.php                |   3 +-
 lib/private/connector/sabre/fakelockerplugin.php   | 159 +++++++++++++++++++
 lib/private/connector/sabre/serverfactory.php      |  38 ++++-
 tests/lib/connector/sabre/FakeLockerPluginTest.php | 173 +++++++++++++++++++++
 .../connector/sabre/requesttest/requesttest.php    |   3 +-
 6 files changed, 375 insertions(+), 4 deletions(-)

diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php
index 02f7f3c..18f368c 100644
--- a/apps/files/appinfo/remote.php
+++ b/apps/files/appinfo/remote.php
@@ -39,7 +39,8 @@ $serverFactory = new \OC\Connector\Sabre\ServerFactory(
 	\OC::$server->getUserSession(),
 	\OC::$server->getMountManager(),
 	\OC::$server->getTagManager(),
-	\OC::$server->getEventDispatcher()
+	\OC::$server->getEventDispatcher(),
+	\OC::$server->getRequest()
 );
 
 // Backends
diff --git a/apps/files_sharing/publicwebdav.php b/apps/files_sharing/publicwebdav.php
index 7d96c8e..a112d71 100644
--- a/apps/files_sharing/publicwebdav.php
+++ b/apps/files_sharing/publicwebdav.php
@@ -39,7 +39,8 @@ $serverFactory = new \OC\Connector\Sabre\ServerFactory(
 	\OC::$server->getUserSession(),
 	\OC::$server->getMountManager(),
 	\OC::$server->getTagManager(),
-	\OC::$server->getEventDispatcher()
+	\OC::$server->getEventDispatcher(),
+	\OC::$server->getRequest()
 );
 
 $requestUri = \OC::$server->getRequest()->getRequestUri();
diff --git a/lib/private/connector/sabre/fakelockerplugin.php b/lib/private/connector/sabre/fakelockerplugin.php
new file mode 100644
index 0000000..8111dea
--- /dev/null
+++ b/lib/private/connector/sabre/fakelockerplugin.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas at 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\Locks\LockInfo;
+use Sabre\DAV\Property\LockDiscovery;
+use Sabre\DAV\Property\SupportedLock;
+use Sabre\DAV\ServerPlugin;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+use Sabre\DAV\PropFind;
+use Sabre\DAV\INode;
+
+/**
+ * Class FakeLockerPlugin is a plugin only used when connections come in from
+ * OS X via Finder. The fake locking plugin does emulate Class 2 WebDAV support
+ * (locking of files) which allows Finder to access the storage in write mode as
+ * well.
+ *
+ * No real locking is performed, instead the plugin just returns always positive
+ * responses.
+ *
+ * @see https://github.com/owncloud/core/issues/17732
+ * @package OC\Connector\Sabre
+ */
+class FakeLockerPlugin extends ServerPlugin {
+	/** @var \Sabre\DAV\Server */
+	private $server;
+
+	/** {@inheritDoc} */
+	public function initialize(\Sabre\DAV\Server $server) {
+		$this->server = $server;
+		$this->server->on('method:LOCK', [$this, 'fakeLockProvider'], 1);
+		$this->server->on('method:UNLOCK', [$this, 'fakeUnlockProvider'], 1);
+		$server->on('propFind', [$this, 'propFind']);
+		$server->on('validateTokens', [$this, 'validateTokens']);
+	}
+
+	/**
+	 * Indicate that we support LOCK and UNLOCK
+	 *
+	 * @param string $path
+	 * @return array
+	 */
+	public function getHTTPMethods($path) {
+		return [
+			'LOCK',
+			'UNLOCK',
+		];
+	}
+
+	/**
+	 * Indicate that we support locking
+	 *
+	 * @return array
+	 */
+	function getFeatures() {
+		return [2];
+	}
+
+	/**
+	 * Return some dummy response for PROPFIND requests with regard to locking
+	 *
+	 * @param PropFind $propFind
+	 * @param INode $node
+	 * @return void
+	 */
+	function propFind(PropFind $propFind, INode $node) {
+		$propFind->handle('{DAV:}supportedlock', function() {
+			return new SupportedLock(true);
+		});
+		$propFind->handle('{DAV:}lockdiscovery', function() use ($propFind) {
+			return new LockDiscovery([]);
+		});
+	}
+
+	/**
+	 * Mark a locking token always as valid
+	 *
+	 * @param RequestInterface $request
+	 * @param array $conditions
+	 */
+	public function validateTokens(RequestInterface $request, &$conditions) {
+		foreach($conditions as &$fileCondition) {
+			if(isset($fileCondition['tokens'])) {
+				foreach($fileCondition['tokens'] as &$token) {
+					if(isset($token['token'])) {
+						if(substr($token['token'], 0, 16) === 'opaquelocktoken:') {
+							$token['validToken'] = true;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Fakes a successful LOCK
+	 *
+	 * @param RequestInterface $request
+	 * @param ResponseInterface $response
+	 * @return bool
+	 */
+	public function fakeLockProvider(RequestInterface $request,
+									 ResponseInterface $response) {
+		$dom = new \DOMDocument('1.0', 'utf-8');
+		$prop = $dom->createElementNS('DAV:', 'd:prop');
+		$dom->appendChild($prop);
+
+		$lockDiscovery = $dom->createElementNS('DAV:', 'd:lockdiscovery');
+		$prop->appendChild($lockDiscovery);
+
+		$lockInfo = new LockInfo();
+		$lockInfo->token = md5($request->getPath());
+		$lockInfo->uri = $request->getPath();
+		$lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
+		$lockInfo->timeout = 1800;
+
+		$lockObj = new LockDiscovery([$lockInfo]);
+		$lockObj->serialize($this->server, $lockDiscovery);
+
+		$response->setBody($dom->saveXML());
+
+		return false;
+	}
+
+	/**
+	 * Fakes a successful LOCK
+	 *
+	 * @param RequestInterface $request
+	 * @param ResponseInterface $response
+	 * @return bool
+	 */
+	public function fakeUnlockProvider(RequestInterface $request,
+									   ResponseInterface $response) {
+		$response->setStatus(204);
+		$response->setHeader('Content-Length', '0');
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/lib/private/connector/sabre/serverfactory.php b/lib/private/connector/sabre/serverfactory.php
index 893e29f..a558a61 100644
--- a/lib/private/connector/sabre/serverfactory.php
+++ b/lib/private/connector/sabre/serverfactory.php
@@ -26,12 +26,40 @@ use OCP\Files\Mount\IMountManager;
 use OCP\IConfig;
 use OCP\IDBConnection;
 use OCP\ILogger;
+use OCP\IRequest;
 use OCP\ITagManager;
 use OCP\IUserSession;
 use Sabre\DAV\Auth\Backend\BackendInterface;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 class ServerFactory {
+	/** @var IConfig */
+	private $config;
+	/** @var ILogger */
+	private $logger;
+	/** @var IDBConnection */
+	private $databaseConnection;
+	/** @var IUserSession */
+	private $userSession;
+	/** @var IMountManager */
+	private $mountManager;
+	/** @var ITagManager */
+	private $tagManager;
+	/** @var EventDispatcherInterface */
+	private $dispatcher;
+	/** @var IRequest */
+	private $request;
+
+	/**
+	 * @param IConfig $config
+	 * @param ILogger $logger
+	 * @param IDBConnection $databaseConnection
+	 * @param IUserSession $userSession
+	 * @param IMountManager $mountManager
+	 * @param ITagManager $tagManager
+	 * @param EventDispatcherInterface $dispatcher
+	 * @param IRequest $request
+	 */
 	public function __construct(
 		IConfig $config,
 		ILogger $logger,
@@ -39,7 +67,8 @@ class ServerFactory {
 		IUserSession $userSession,
 		IMountManager $mountManager,
 		ITagManager $tagManager,
-		EventDispatcherInterface $dispatcher
+		EventDispatcherInterface $dispatcher,
+		IRequest $request
 	) {
 		$this->config = $config;
 		$this->logger = $logger;
@@ -48,6 +77,7 @@ class ServerFactory {
 		$this->mountManager = $mountManager;
 		$this->tagManager = $tagManager;
 		$this->dispatcher = $dispatcher;
+		$this->request = $request;
 	}
 
 	/**
@@ -76,6 +106,12 @@ class ServerFactory {
 		$server->addPlugin(new \OC\Connector\Sabre\LockPlugin($objectTree));
 		$server->addPlugin(new \OC\Connector\Sabre\ListenerPlugin($this->dispatcher));
 
+		// Finder on OS X requires Class 2 WebDAV support (locking), since we do
+		// not provide locking we emulate it using a fake locking plugin.
+		if($this->request->isUserAgent(['/WebDAVFS/'])) {
+			$server->addPlugin(new \OC\Connector\Sabre\FakeLockerPlugin());
+		}
+
 		// 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 */
diff --git a/tests/lib/connector/sabre/FakeLockerPluginTest.php b/tests/lib/connector/sabre/FakeLockerPluginTest.php
new file mode 100644
index 0000000..2dc6e73
--- /dev/null
+++ b/tests/lib/connector/sabre/FakeLockerPluginTest.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas at 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 OCA\DAV\Tests\Unit\Connector\Sabre;
+
+use OC\Connector\Sabre\FakeLockerPlugin;
+use Test\TestCase;
+
+/**
+ * Class FakeLockerPluginTest
+ *
+ * @package OC\DAV\Tests\Unit\Connector\Sabre
+ */
+class FakeLockerPluginTest extends TestCase {
+	/** @var FakeLockerPlugin */
+	private $fakeLockerPlugin;
+
+	public function setUp() {
+		parent::setUp();
+		$this->fakeLockerPlugin = new FakeLockerPlugin();
+	}
+
+	public function testInitialize() {
+		/** @var \Sabre\DAV\Server $server */
+		$server = $this->getMock('\Sabre\DAV\Server');
+		$server
+			->expects($this->at(0))
+			->method('on')
+			->with('method:LOCK', [$this->fakeLockerPlugin, 'fakeLockProvider'], 1);
+		$server
+			->expects($this->at(1))
+			->method('on')
+			->with('method:UNLOCK', [$this->fakeLockerPlugin, 'fakeUnlockProvider'], 1);
+		$server
+			->expects($this->at(2))
+			->method('on')
+			->with('propFind', [$this->fakeLockerPlugin, 'propFind']);
+		$server
+			->expects($this->at(3))
+			->method('on')
+			->with('validateTokens', [$this->fakeLockerPlugin, 'validateTokens']);
+
+		$this->fakeLockerPlugin->initialize($server);
+	}
+
+	public function testGetHTTPMethods() {
+		$expected = [
+			'LOCK',
+			'UNLOCK',
+		];
+		$this->assertSame($expected, $this->fakeLockerPlugin->getHTTPMethods('Test'));
+	}
+
+	public function testGetFeatures() {
+		$expected = [
+			2,
+		];
+		$this->assertSame($expected, $this->fakeLockerPlugin->getFeatures());
+	}
+
+	public function testPropFind() {
+		$propFind = $this->getMockBuilder('\Sabre\DAV\PropFind')
+			->disableOriginalConstructor()
+			->getMock();
+		$node = $this->getMock('\Sabre\DAV\INode');
+
+		$propFind->expects($this->at(0))
+			->method('handle')
+			->with('{DAV:}supportedlock');
+		$propFind->expects($this->at(1))
+			->method('handle')
+			->with('{DAV:}lockdiscovery');
+
+		$this->fakeLockerPlugin->propFind($propFind, $node);
+	}
+
+	public function tokenDataProvider() {
+		return [
+			[
+				[
+					[
+						'tokens' => [
+							[
+								'token' => 'aToken',
+								'validToken' => false,
+							],
+							[],
+							[
+								'token' => 'opaquelocktoken:asdf',
+								'validToken' => false,
+							]
+						],
+					]
+				],
+				[
+					[
+						'tokens' => [
+							[
+								'token' => 'aToken',
+								'validToken' => false,
+							],
+							[],
+							[
+								'token' => 'opaquelocktoken:asdf',
+								'validToken' => true,
+							]
+						],
+					]
+				],
+			]
+		];
+	}
+
+	/**
+	 * @dataProvider tokenDataProvider
+	 * @param array $input
+	 * @param array $expected
+	 */
+	public function testValidateTokens(array $input, array $expected) {
+		$request = $this->getMock('\Sabre\HTTP\RequestInterface');
+		$this->fakeLockerPlugin->validateTokens($request, $input);
+		$this->assertSame($expected, $input);
+	}
+
+	public function testFakeLockProvider() {
+		$request = $this->getMock('\Sabre\HTTP\RequestInterface');
+		$response = $this->getMock('\Sabre\HTTP\ResponseInterface');
+		$server = $this->getMock('\Sabre\DAV\Server');
+		$this->fakeLockerPlugin->initialize($server);
+
+		$request->expects($this->exactly(2))
+			->method('getPath')
+			->will($this->returnValue('MyPath'));
+		$response->expects($this->once())
+			->method('setBody')
+			->with('<?xml version="1.0" encoding="utf-8"?>
+<d:prop xmlns:d="DAV:"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop>
+');
+
+		$this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response));
+	}
+
+	public function testFakeUnlockProvider() {
+		$request = $this->getMock('\Sabre\HTTP\RequestInterface');
+		$response = $this->getMock('\Sabre\HTTP\ResponseInterface');
+
+		$response->expects($this->once())
+			->method('setStatus')
+			->with('204');
+		$response->expects($this->once())
+			->method('setHeader')
+			->with('Content-Length', '0');
+
+		$this->assertSame(false, $this->fakeLockerPlugin->fakeUnlockProvider($request, $response));
+	}
+}
\ No newline at end of file
diff --git a/tests/lib/connector/sabre/requesttest/requesttest.php b/tests/lib/connector/sabre/requesttest/requesttest.php
index 4d4c817..225213c 100644
--- a/tests/lib/connector/sabre/requesttest/requesttest.php
+++ b/tests/lib/connector/sabre/requesttest/requesttest.php
@@ -46,7 +46,8 @@ abstract class RequestTest extends TestCase {
 			\OC::$server->getUserSession(),
 			\OC::$server->getMountManager(),
 			\OC::$server->getTagManager(),
-			\OC::$server->getEventDispatcher()
+			\OC::$server->getEventDispatcher(),
+			$this->getMock('\OCP\IRequest')
 		);
 	}
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list