Completed
Push — master ( e4992c...6d0a35 )
by
unknown
10:42
created

Server   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 246
Duplicated Lines 3.25 %

Coupling/Cohesion

Components 1
Dependencies 57

Importance

Changes 0
Metric Value
dl 8
loc 246
rs 10
c 0
b 0
f 0
wmc 16
lcom 1
cbo 57

3 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 8 211 12
A exec() 0 3 1
A isRequestForSubtree() 0 9 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @author Christoph Wurst <[email protected]>
4
 * @author Georg Ehrke <[email protected]>
5
 * @author Lukas Reschke <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Thomas Citharel <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 * @author Vincent Petry <[email protected]>
10
 *
11
 * @copyright Copyright (c) 2018, ownCloud GmbH
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
namespace OCA\DAV;
28
29
use OC\Files\Filesystem;
30
use OCA\DAV\AppInfo\PluginManager;
31
use OCA\DAV\CalDAV\Schedule\IMipPlugin;
32
use OCA\DAV\CardDAV\ImageExportPlugin;
33
use OCA\DAV\Connector\Sabre\Auth;
34
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
35
use OCA\DAV\Connector\Sabre\CommentPropertiesPlugin;
36
use OCA\DAV\Connector\Sabre\CopyEtagHeaderPlugin;
37
use OCA\DAV\Connector\Sabre\CorsPlugin;
38
use OCA\DAV\Connector\Sabre\DavAclPlugin;
39
use OCA\DAV\Connector\Sabre\DummyGetResponsePlugin;
40
use OCA\DAV\Connector\Sabre\FakeLockerPlugin;
41
use OCA\DAV\Connector\Sabre\FilesPlugin;
42
use OCA\DAV\Connector\Sabre\FilesReportPlugin;
43
use OCA\DAV\Connector\Sabre\MaintenancePlugin;
44
use OCA\DAV\Connector\Sabre\QuotaPlugin;
45
use OCA\DAV\Connector\Sabre\SharesPlugin;
46
use OCA\DAV\Connector\Sabre\TagsPlugin;
47
use OCA\DAV\Connector\Sabre\ValidateRequestPlugin;
48
use OCA\DAV\DAV\FileCustomPropertiesBackend;
49
use OCA\DAV\DAV\FileCustomPropertiesPlugin;
50
use OCA\DAV\DAV\MiscCustomPropertiesBackend;
51
use OCA\DAV\DAV\PublicAuth;
52
use OCA\DAV\Files\BrowserErrorPagePlugin;
53
use OCA\DAV\Files\PreviewPlugin;
54
use OCA\DAV\Files\ZsyncPlugin;
55
use OCA\DAV\SystemTag\SystemTagPlugin;
56
use OCA\DAV\Upload\ChunkingPlugin;
57
use OCA\DAV\Upload\ChunkingPluginZsync;
58
use OCP\IRequest;
59
use OCP\SabrePluginEvent;
60
use Sabre\CardDAV\VCFExportPlugin;
61
use Sabre\DAV\Auth\Plugin;
62
63
class Server {
64
65
	/** @var Connector\Sabre\Server  */
66
	public $server;
67
68
	/** @var string */
69
	private $baseUri;
70
	/** @var IRequest */
71
	private $request;
72
73
	/**
74
	 * Server constructor.
75
	 *
76
	 * @param IRequest $request
77
	 * @param string $baseUri
78
	 */
79
	public function __construct(IRequest $request, $baseUri) {
80
		$this->request = $request;
81
		$this->baseUri = $baseUri;
82
		$logger = \OC::$server->getLogger();
83
		$dispatcher = \OC::$server->getEventDispatcher();
84
85
		$root = new RootCollection();
86
		$tree = new \OCA\DAV\Tree($root);
87
		$this->server = new \OCA\DAV\Connector\Sabre\Server($tree);
88
89
		// Backends
90
		$authBackend = new Auth(
91
			\OC::$server->getSession(),
92
			\OC::$server->getUserSession(),
93
			\OC::$server->getRequest(),
94
			\OC::$server->getTwoFactorAuthManager()
95
		);
96
97
		// Set URL explicitly due to reverse-proxy situations
98
		$this->server->httpRequest->setUrl($this->request->getRequestUri());
99
		$this->server->setBaseUri($this->baseUri);
100
101
		$config = \OC::$server->getConfig();
102
		$this->server->addPlugin(new MaintenancePlugin($config));
103
		$this->server->addPlugin(new ValidateRequestPlugin('dav'));
104
		$this->server->addPlugin(new BlockLegacyClientPlugin($config));
105
		$this->server->addPlugin(new CorsPlugin(\OC::$server->getUserSession()));
106
		$authPlugin = new Plugin();
107
		$authPlugin->addBackend(new PublicAuth());
108
		$this->server->addPlugin($authPlugin);
109
110
		// allow setup of additional auth backends
111
		$event = new SabrePluginEvent($this->server);
112
		$dispatcher->dispatch('OCA\DAV\Connector\Sabre::authInit', $event);
113
114
		// because we are throwing exceptions this plugin has to be the last one
115
		$authPlugin->addBackend($authBackend);
116
117
		// debugging
118
		if (\OC::$server->getConfig()->getSystemValue('debug', false)) {
119
			$this->server->addPlugin(new \Sabre\DAV\Browser\Plugin());
120
		} else {
121
			$this->server->addPlugin(new DummyGetResponsePlugin());
122
		}
123
124
		$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $logger));
125
		$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
126
		$this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
127
128
		// ACL plugin not used in files subtree, also it causes issues
129
		// with performance and locking issues because it will query
130
		// every parent node which might trigger an implicit rescan in the
131
		// case of external storages with update detection
132
		if (!$this->isRequestForSubtree(['files'])) {
133
			// acl
134
			$acl = new DavAclPlugin();
135
			$acl->principalCollectionSet = [
136
				'principals/users', 'principals/groups'
137
			];
138
			$acl->defaultUsernamePath = 'principals/users';
0 ignored issues
show
Bug introduced by
The property defaultUsernamePath does not seem to exist in OCA\DAV\Connector\Sabre\DavAclPlugin.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
139
			$this->server->addPlugin($acl);
140
		}
141
142
		// calendar plugins
143
		if ($this->isRequestForSubtree(['calendars', 'public-calendars', 'principals'])) {
144
			$mailer = \OC::$server->getMailer();
145
			$this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
146
			$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
147
			$this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
148
			$this->server->addPlugin(new IMipPlugin($mailer, $logger, $request));
149
			$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
150
			$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
151
			$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
152
			$this->server->addPlugin(new \OCA\DAV\CalDAV\Publishing\PublishPlugin(
153
				\OC::$server->getConfig(),
154
				\OC::$server->getURLGenerator()
155
			));
156
		}
157
158
		// addressbook plugins
159
		if ($this->isRequestForSubtree(['addressbooks', 'principals'])) {
160
			$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
161
			$this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin());
162
			$this->server->addPlugin(new VCFExportPlugin());
163
			$this->server->addPlugin(new ImageExportPlugin(\OC::$server->getLogger()));
164
		}
165
166
		// system tags plugins
167
		$this->server->addPlugin(new SystemTagPlugin(
168
			\OC::$server->getSystemTagManager(),
169
			\OC::$server->getGroupManager(),
170
			\OC::$server->getUserSession()
171
		));
172
173
		$this->server->addPlugin(new CopyEtagHeaderPlugin());
174
		$this->server->addPlugin(new ChunkingPlugin());
175
176
		// Some WebDAV clients do require Class 2 WebDAV support (locking), since
177
		// we do not provide locking we emulate it using a fake locking plugin.
178 View Code Duplication
		if ($request->isUserAgent([
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
			'/WebDAVFS/',
180
			'/OneNote/',
181
			'/Microsoft Office OneNote 2013/',
182
			'/Microsoft-WebDAV-MiniRedir/',
183
		])) {
184
			$this->server->addPlugin(new FakeLockerPlugin());
185
		}
186
187
		if (BrowserErrorPagePlugin::isBrowserRequest($request)) {
188
			$this->server->addPlugin(new BrowserErrorPagePlugin());
189
		}
190
191
		$this->server->addPlugin(new PreviewPlugin(\OC::$server->getTimeFactory(), \OC::$server->getPreviewManager()));
192
		// wait with registering these until auth is handled and the filesystem is setup
193
		$this->server->on('beforeMethod', function () use ($root) {
194
			// custom properties plugin must be the last one
195
			$userSession = \OC::$server->getUserSession();
196
			$user = $userSession->getUser();
197
			if ($user !== null) {
198
				$userHomeView = new \OC\Files\View('/'.$user->getUID());
199
				$this->server->addPlugin(
200
					new ChunkingPluginZsync($userHomeView)
201
				);
202
203
				$this->server->addPlugin(
204
					new ZsyncPlugin($userHomeView)
205
				);
206
207
				$view = \OC\Files\Filesystem::getView();
208
				$this->server->addPlugin(
209
					new FilesPlugin(
210
						$this->server->tree,
211
						\OC::$server->getConfig(),
212
						$this->request,
213
						false,
214
						!\OC::$server->getConfig()->getSystemValue('debug', false)
215
					)
216
				);
217
218
				$filePropertiesPlugin = new FileCustomPropertiesPlugin(
219
					new FileCustomPropertiesBackend(
220
						$this->server->tree,
221
						\OC::$server->getDatabaseConnection(),
222
						\OC::$server->getUserSession()->getUser()
0 ignored issues
show
Bug introduced by
It seems like \OC::$server->getUserSession()->getUser() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
223
					)
224
				);
225
				$filePropertiesPlugin->pathFilter = function ($path) {
226
					// oh yes, we could set custom properties on the user's storage root
227
					return \strpos($path, 'files/') === 0;
228
				};
229
				$this->server->addPlugin($filePropertiesPlugin);
230
231
				$miscPropertiesPlugin = new \Sabre\DAV\PropertyStorage\Plugin(
232
					new MiscCustomPropertiesBackend(
233
						$this->server->tree,
234
						\OC::$server->getDatabaseConnection(),
235
						\OC::$server->getUserSession()->getUser()
0 ignored issues
show
Bug introduced by
It seems like \OC::$server->getUserSession()->getUser() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
236
					)
237
				);
238
				$miscPropertiesPlugin->pathFilter = function ($path) {
239
					return \strpos($path, 'files/') !== 0;
240
				};
241
				$this->server->addPlugin($miscPropertiesPlugin);
242
243
				if ($view !== null) {
244
					$this->server->addPlugin(
245
						new QuotaPlugin($view));
246
				}
247
				$this->server->addPlugin(
248
					new TagsPlugin(
249
						$this->server->tree, \OC::$server->getTagManager()
250
					)
251
				);
252
				// TODO: switch to LazyUserFolder
253
				$userFolder = \OC::$server->getUserFolder();
254
				$this->server->addPlugin(new SharesPlugin(
255
					$this->server->tree,
256
					$userSession,
257
					\OC::$server->getShareManager()
258
				));
259
				$this->server->addPlugin(new CommentPropertiesPlugin(
260
					\OC::$server->getCommentsManager(),
261
					$userSession
262
				));
263
				if ($view !== null) {
264
					$this->server->addPlugin(new FilesReportPlugin(
265
						$this->server->tree,
266
						$view,
267
						\OC::$server->getSystemTagManager(),
268
						\OC::$server->getSystemTagObjectMapper(),
269
						\OC::$server->getTagManager(),
270
						$userSession,
271
						\OC::$server->getGroupManager(),
272
						$userFolder
0 ignored issues
show
Bug introduced by
It seems like $userFolder defined by \OC::$server->getUserFolder() on line 253 can be null; however, OCA\DAV\Connector\Sabre\...rtPlugin::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
273
					));
274
				}
275
			}
276
277
			// register plugins from apps
278
			$pluginManager = new PluginManager(
279
				\OC::$server,
280
				\OC::$server->getAppManager()
281
			);
282
			foreach ($pluginManager->getAppPlugins() as $appPlugin) {
283
				$this->server->addPlugin($appPlugin);
284
			}
285
			foreach ($pluginManager->getAppCollections() as $appCollection) {
286
				$root->addChild($appCollection);
287
			}
288
		});
289
	}
290
291
	public function exec() {
292
		$this->server->exec();
293
	}
294
295
	/**
296
	 * @param string[] $subTree
0 ignored issues
show
Documentation introduced by
There is no parameter named $subTree. Did you maybe mean $subTrees?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
297
	 * @return bool
298
	 */
299
	private function isRequestForSubtree(array $subTrees) {
300
		foreach ($subTrees as $subTree) {
301
			$subTree = \trim($subTree, " /");
302
			if (\strpos($this->server->getRequestUri(), "$subTree/") === 0) {
303
				return true;
304
			}
305
		}
306
		return false;
307
	}
308
}
309