Passed
Push — master ( f1cc6c...fa7364 )
by Julius
15:37 queued 12s
created

DIContainer::query()   B

Complexity

Conditions 9
Paths 11

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 9
eloc 14
c 2
b 0
f 0
nc 11
nop 2
dl 0
loc 20
rs 8.0555
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bernhard Posselt <[email protected]>
7
 * @author Bjoern Schiessle <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Joas Schilling <[email protected]>
10
 * @author Jörn Friedrich Dreyer <[email protected]>
11
 * @author Lukas Reschke <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Robin McCorkell <[email protected]>
14
 * @author Roeland Jago Douma <[email protected]>
15
 * @author Sebastian Wessalowski <[email protected]>
16
 * @author Thomas Müller <[email protected]>
17
 * @author Thomas Tanghus <[email protected]>
18
 *
19
 * @license AGPL-3.0
20
 *
21
 * This code is free software: you can redistribute it and/or modify
22
 * it under the terms of the GNU Affero General Public License, version 3,
23
 * as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License, version 3,
31
 * along with this program. If not, see <http://www.gnu.org/licenses/>
32
 *
33
 */
34
namespace OC\AppFramework\DependencyInjection;
35
36
use OC;
37
use OC\AppFramework\Http;
38
use OC\AppFramework\Http\Dispatcher;
39
use OC\AppFramework\Http\Output;
40
use OC\AppFramework\Middleware\MiddlewareDispatcher;
41
use OC\AppFramework\Middleware\OCSMiddleware;
42
use OC\AppFramework\Middleware\Security\CORSMiddleware;
43
use OC\AppFramework\Middleware\Security\RateLimitingMiddleware;
44
use OC\AppFramework\Middleware\Security\SecurityMiddleware;
45
use OC\AppFramework\Middleware\SessionMiddleware;
46
use OC\AppFramework\ScopedPsrLogger;
47
use OC\AppFramework\Utility\SimpleContainer;
48
use OC\Core\Middleware\TwoFactorMiddleware;
49
use OC\Diagnostics\EventLogger;
50
use OC\Log\PsrLoggerAdapter;
51
use OC\ServerContainer;
52
use OC\Settings\AuthorizedGroupMapper;
53
use OCA\WorkflowEngine\Manager;
54
use OCP\AppFramework\Http\IOutput;
55
use OCP\AppFramework\IAppContainer;
56
use OCP\AppFramework\QueryException;
57
use OCP\AppFramework\Services\IAppConfig;
58
use OCP\AppFramework\Services\IInitialState;
59
use OCP\AppFramework\Utility\IControllerMethodReflector;
60
use OCP\AppFramework\Utility\ITimeFactory;
61
use OCP\Files\Folder;
62
use OCP\Files\IAppData;
63
use OCP\Group\ISubAdmin;
64
use OCP\IConfig;
65
use OCP\IDBConnection;
66
use OCP\IInitialStateService;
67
use OCP\IL10N;
68
use OCP\ILogger;
69
use OCP\INavigationManager;
70
use OCP\IRequest;
71
use OCP\IServerContainer;
72
use OCP\ISession;
73
use OCP\IURLGenerator;
74
use OCP\IUserSession;
75
use Psr\Container\ContainerInterface;
76
use Psr\Log\LoggerInterface;
77
78
/**
79
 * @deprecated 20.0.0
80
 */
81
class DIContainer extends SimpleContainer implements IAppContainer {
0 ignored issues
show
Deprecated Code introduced by
The interface OCP\AppFramework\IAppContainer has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

81
class DIContainer extends SimpleContainer implements /** @scrutinizer ignore-deprecated */ IAppContainer {

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
82
	private string $appName;
83
84
	/**
85
	 * @var array
86
	 */
87
	private $middleWares = [];
88
89
	/** @var ServerContainer */
90
	private $server;
91
92
	/**
93
	 * Put your class dependencies in here
94
	 * @param string $appName the name of the app
95
	 * @param array $urlParams
96
	 * @param ServerContainer|null $server
97
	 */
98
	public function __construct(string $appName, array $urlParams = [], ServerContainer $server = null) {
99
		parent::__construct();
100
		$this->appName = $appName;
101
		$this['appName'] = $appName;
102
		$this['urlParams'] = $urlParams;
103
104
		$this->registerAlias('Request', IRequest::class);
105
106
		/** @var \OC\ServerContainer $server */
107
		if ($server === null) {
108
			$server = \OC::$server;
109
		}
110
		$this->server = $server;
111
		$this->server->registerAppContainer($appName, $this);
112
113
		// aliases
114
		/** @deprecated inject $appName */
115
		$this->registerAlias('AppName', 'appName');
116
		/** @deprecated inject $webRoot*/
117
		$this->registerAlias('WebRoot', 'webRoot');
118
		/** @deprecated inject $userId */
119
		$this->registerAlias('UserId', 'userId');
120
121
		/**
122
		 * Core services
123
		 */
124
		$this->registerService(IOutput::class, function () {
125
			return new Output($this->getServer()->getWebRoot());
126
		});
127
128
		$this->registerService(Folder::class, function () {
129
			return $this->getServer()->getUserFolder();
130
		});
131
132
		$this->registerService(IAppData::class, function (ContainerInterface $c) {
133
			return $this->getServer()->getAppDataDir($c->get('AppName'));
0 ignored issues
show
Bug introduced by
The method getAppDataDir() does not exist on OCP\IServerContainer. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\IServerContainer. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

133
			return $this->getServer()->/** @scrutinizer ignore-call */ getAppDataDir($c->get('AppName'));
Loading history...
134
		});
135
136
		$this->registerService(IL10N::class, function (ContainerInterface $c) {
137
			return $this->getServer()->getL10N($c->get('AppName'));
138
		});
139
140
		// Log wrappers
141
		$this->registerService(LoggerInterface::class, function (ContainerInterface $c) {
142
			return new ScopedPsrLogger(
143
				$c->get(PsrLoggerAdapter::class),
144
				$c->get('AppName')
145
			);
146
		});
147
		$this->registerService(ILogger::class, function (ContainerInterface $c) {
148
			return new OC\AppFramework\Logger($this->server->query(ILogger::class), $c->get('AppName'));
0 ignored issues
show
Deprecated Code introduced by
The class OC\AppFramework\Logger has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

148
			return /** @scrutinizer ignore-deprecated */ new OC\AppFramework\Logger($this->server->query(ILogger::class), $c->get('AppName'));
Loading history...
149
		});
150
151
		$this->registerService(IServerContainer::class, function () {
152
			return $this->getServer();
153
		});
154
		$this->registerAlias('ServerContainer', IServerContainer::class);
155
156
		$this->registerService(\OCP\WorkflowEngine\IManager::class, function (ContainerInterface $c) {
157
			return $c->get(Manager::class);
158
		});
159
160
		$this->registerService(ContainerInterface::class, function (ContainerInterface $c) {
161
			return $c;
162
		});
163
		$this->registerAlias(IAppContainer::class, ContainerInterface::class);
164
165
		// commonly used attributes
166
		$this->registerService('userId', function (ContainerInterface $c) {
167
			return $c->get(IUserSession::class)->getSession()->get('user_id');
168
		});
169
170
		$this->registerService('webRoot', function (ContainerInterface $c) {
171
			return $c->get(IServerContainer::class)->getWebRoot();
172
		});
173
174
		$this->registerService('OC_Defaults', function (ContainerInterface $c) {
175
			return $c->get(IServerContainer::class)->getThemingDefaults();
176
		});
177
178
		$this->registerService('Protocol', function (ContainerInterface $c) {
179
			/** @var \OC\Server $server */
180
			$server = $c->get(IServerContainer::class);
181
			$protocol = $server->getRequest()->getHttpProtocol();
182
			return new Http($_SERVER, $protocol);
183
		});
184
185
		$this->registerService('Dispatcher', function (ContainerInterface $c) {
186
			return new Dispatcher(
187
				$c->get('Protocol'),
188
				$c->get(MiddlewareDispatcher::class),
189
				$c->get(IControllerMethodReflector::class),
190
				$c->get(IRequest::class),
191
				$c->get(IConfig::class),
192
				$c->get(IDBConnection::class),
193
				$c->get(LoggerInterface::class),
194
				$c->get(EventLogger::class)
195
			);
196
		});
197
198
		/**
199
		 * App Framework default arguments
200
		 */
201
		$this->registerParameter('corsMethods', 'PUT, POST, GET, DELETE, PATCH');
202
		$this->registerParameter('corsAllowedHeaders', 'Authorization, Content-Type, Accept');
203
		$this->registerParameter('corsMaxAge', 1728000);
204
205
		/**
206
		 * Middleware
207
		 */
208
		$this->registerAlias('MiddlewareDispatcher', MiddlewareDispatcher::class);
209
		$this->registerService(MiddlewareDispatcher::class, function (ContainerInterface $c) {
210
			$server = $this->getServer();
211
212
			$dispatcher = new MiddlewareDispatcher();
213
214
			$dispatcher->registerMiddleware(
215
				$c->get(OC\AppFramework\Middleware\CompressionMiddleware::class)
216
			);
217
218
			$dispatcher->registerMiddleware($c->get(OC\AppFramework\Middleware\NotModifiedMiddleware::class));
219
220
			$dispatcher->registerMiddleware(
221
				$c->get(OC\AppFramework\Middleware\Security\ReloadExecutionMiddleware::class)
222
			);
223
224
			$dispatcher->registerMiddleware(
225
				new OC\AppFramework\Middleware\Security\SameSiteCookieMiddleware(
226
					$c->get(IRequest::class),
227
					$c->get(IControllerMethodReflector::class)
228
				)
229
			);
230
			$dispatcher->registerMiddleware(
231
				new CORSMiddleware(
232
					$c->get(IRequest::class),
233
					$c->get(IControllerMethodReflector::class),
234
					$c->get(IUserSession::class),
235
					$c->get(OC\Security\Bruteforce\Throttler::class)
236
				)
237
			);
238
			$dispatcher->registerMiddleware(
239
				new OCSMiddleware(
240
					$c->get(IRequest::class)
241
				)
242
			);
243
244
245
246
			$securityMiddleware = new SecurityMiddleware(
247
				$c->get(IRequest::class),
248
				$c->get(IControllerMethodReflector::class),
249
				$c->get(INavigationManager::class),
250
				$c->get(IURLGenerator::class),
251
				$server->get(LoggerInterface::class),
252
				$c->get('AppName'),
253
				$server->getUserSession()->isLoggedIn(),
254
				$this->getUserId() !== null && $server->getGroupManager()->isAdmin($this->getUserId()),
255
				$server->getUserSession()->getUser() !== null && $server->query(ISubAdmin::class)->isSubAdmin($server->getUserSession()->getUser()),
256
				$server->getAppManager(),
257
				$server->getL10N('lib'),
258
				$c->get(AuthorizedGroupMapper::class),
259
				$server->get(IUserSession::class)
260
			);
261
			$dispatcher->registerMiddleware($securityMiddleware);
262
			$dispatcher->registerMiddleware(
263
				new OC\AppFramework\Middleware\Security\CSPMiddleware(
264
					$server->query(OC\Security\CSP\ContentSecurityPolicyManager::class),
265
					$server->query(OC\Security\CSP\ContentSecurityPolicyNonceManager::class),
266
					$server->query(OC\Security\CSRF\CsrfTokenManager::class)
267
				)
268
			);
269
			$dispatcher->registerMiddleware(
270
				$server->query(OC\AppFramework\Middleware\Security\FeaturePolicyMiddleware::class)
271
			);
272
			$dispatcher->registerMiddleware(
273
				new OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware(
274
					$c->get(IControllerMethodReflector::class),
275
					$c->get(ISession::class),
276
					$c->get(IUserSession::class),
277
					$c->get(ITimeFactory::class)
278
				)
279
			);
280
			$dispatcher->registerMiddleware(
281
				new TwoFactorMiddleware(
282
					$c->get(OC\Authentication\TwoFactorAuth\Manager::class),
283
					$c->get(IUserSession::class),
284
					$c->get(ISession::class),
285
					$c->get(IURLGenerator::class),
286
					$c->get(IControllerMethodReflector::class),
287
					$c->get(IRequest::class)
288
				)
289
			);
290
			$dispatcher->registerMiddleware(
291
				new OC\AppFramework\Middleware\Security\BruteForceMiddleware(
292
					$c->get(IControllerMethodReflector::class),
293
					$c->get(OC\Security\Bruteforce\Throttler::class),
294
					$c->get(IRequest::class)
295
				)
296
			);
297
			$dispatcher->registerMiddleware(
298
				new RateLimitingMiddleware(
299
					$c->get(IRequest::class),
300
					$c->get(IUserSession::class),
301
					$c->get(IControllerMethodReflector::class),
302
					$c->get(OC\Security\RateLimiting\Limiter::class)
303
				)
304
			);
305
			$dispatcher->registerMiddleware(
306
				new OC\AppFramework\Middleware\PublicShare\PublicShareMiddleware(
307
					$c->get(IRequest::class),
308
					$c->get(ISession::class),
309
					$c->get(\OCP\IConfig::class),
310
					$c->get(OC\Security\Bruteforce\Throttler::class)
311
				)
312
			);
313
			$dispatcher->registerMiddleware(
314
				$c->get(\OC\AppFramework\Middleware\AdditionalScriptsMiddleware::class)
315
			);
316
317
			foreach ($this->middleWares as $middleWare) {
318
				$dispatcher->registerMiddleware($c->get($middleWare));
319
			}
320
321
			$dispatcher->registerMiddleware(
322
				new SessionMiddleware(
323
					$c->get(IControllerMethodReflector::class),
324
					$c->get(ISession::class)
325
				)
326
			);
327
			return $dispatcher;
328
		});
329
330
		$this->registerService(IAppConfig::class, function (ContainerInterface $c) {
331
			return new OC\AppFramework\Services\AppConfig(
332
				$c->get(IConfig::class),
333
				$c->get('AppName')
334
			);
335
		});
336
		$this->registerService(IInitialState::class, function (ContainerInterface $c) {
337
			return new OC\AppFramework\Services\InitialState(
338
				$c->get(IInitialStateService::class),
339
				$c->get('AppName')
340
			);
341
		});
342
	}
343
344
	/**
345
	 * @return \OCP\IServerContainer
346
	 */
347
	public function getServer() {
348
		return $this->server;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->server returns the type OC\ServerContainer which is incompatible with the documented return type OCP\IServerContainer.
Loading history...
349
	}
350
351
	/**
352
	 * @param string $middleWare
353
	 * @return boolean|null
354
	 */
355
	public function registerMiddleWare($middleWare) {
356
		if (in_array($middleWare, $this->middleWares, true) !== false) {
357
			return false;
358
		}
359
		$this->middleWares[] = $middleWare;
360
	}
361
362
	/**
363
	 * used to return the appname of the set application
364
	 * @return string the name of your application
365
	 */
366
	public function getAppName() {
367
		return $this->query('AppName');
368
	}
369
370
	/**
371
	 * @deprecated use IUserSession->isLoggedIn()
372
	 * @return boolean
373
	 */
374
	public function isLoggedIn() {
375
		return \OC::$server->getUserSession()->isLoggedIn();
376
	}
377
378
	/**
379
	 * @deprecated use IGroupManager->isAdmin($userId)
380
	 * @return boolean
381
	 */
382
	public function isAdminUser() {
383
		$uid = $this->getUserId();
384
		return \OC_User::isAdminUser($uid);
385
	}
386
387
	private function getUserId() {
388
		return $this->getServer()->getSession()->get('user_id');
389
	}
390
391
	/**
392
	 * @deprecated use the ILogger instead
393
	 * @param string $message
394
	 * @param string $level
395
	 * @return mixed
396
	 */
397
	public function log($message, $level) {
398
		switch ($level) {
399
			case 'debug':
400
				$level = ILogger::DEBUG;
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::DEBUG has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

400
				$level = /** @scrutinizer ignore-deprecated */ ILogger::DEBUG;

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
401
				break;
402
			case 'info':
403
				$level = ILogger::INFO;
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::INFO has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

403
				$level = /** @scrutinizer ignore-deprecated */ ILogger::INFO;

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
404
				break;
405
			case 'warn':
406
				$level = ILogger::WARN;
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::WARN has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

406
				$level = /** @scrutinizer ignore-deprecated */ ILogger::WARN;

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
407
				break;
408
			case 'fatal':
409
				$level = ILogger::FATAL;
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::FATAL has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

409
				$level = /** @scrutinizer ignore-deprecated */ ILogger::FATAL;

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
410
				break;
411
			default:
412
				$level = ILogger::ERROR;
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::ERROR has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

412
				$level = /** @scrutinizer ignore-deprecated */ ILogger::ERROR;

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
413
				break;
414
		}
415
		\OCP\Util::writeLog($this->getAppName(), $message, $level);
416
	}
417
418
	/**
419
	 * Register a capability
420
	 *
421
	 * @param string $serviceName e.g. 'OCA\Files\Capabilities'
422
	 */
423
	public function registerCapability($serviceName) {
424
		$this->query('OC\CapabilitiesManager')->registerCapability(function () use ($serviceName) {
425
			return $this->query($serviceName);
426
		});
427
	}
428
429
	public function has($id): bool {
430
		if (parent::has($id)) {
431
			return true;
432
		}
433
434
		if ($this->server->has($id, true)) {
435
			return true;
436
		}
437
438
		return false;
439
	}
440
441
	public function query(string $name, bool $autoload = true) {
442
		if ($name === 'AppName' || $name === 'appName') {
443
			return $this->appName;
444
		}
445
446
		$isServerClass = str_starts_with($name, 'OCP\\') || str_starts_with($name, 'OC\\');
447
		if ($isServerClass && !$this->has($name)) {
448
			return $this->getServer()->query($name, $autoload);
449
		}
450
451
		try {
452
			return $this->queryNoFallback($name);
453
		} catch (QueryException $firstException) {
454
			try {
455
				return $this->getServer()->query($name, $autoload);
456
			} catch (QueryException $secondException) {
457
				if ($firstException->getCode() === 1) {
458
					throw $secondException;
459
				}
460
				throw $firstException;
461
			}
462
		}
463
	}
464
465
	/**
466
	 * @param string $name
467
	 * @return mixed
468
	 * @throws QueryException if the query could not be resolved
469
	 */
470
	public function queryNoFallback($name) {
471
		$name = $this->sanitizeName($name);
472
473
		if ($this->offsetExists($name)) {
474
			return parent::query($name);
475
		} elseif ($this->appName === 'settings' && str_starts_with($name, 'OC\\Settings\\')) {
476
			return parent::query($name);
477
		} elseif ($this->appName === 'core' && str_starts_with($name, 'OC\\Core\\')) {
478
			return parent::query($name);
479
		} elseif (str_starts_with($name, \OC\AppFramework\App::buildAppNamespace($this->appName) . '\\')) {
480
			return parent::query($name);
481
		}
482
483
		throw new QueryException('Could not resolve ' . $name . '!' .
0 ignored issues
show
Deprecated Code introduced by
The class OCP\AppFramework\QueryException has been deprecated: 20.0.0 catch \Psr\Container\ContainerExceptionInterface ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

483
		throw /** @scrutinizer ignore-deprecated */ new QueryException('Could not resolve ' . $name . '!' .
Loading history...
484
			' Class can not be instantiated', 1);
485
	}
486
}
487