Passed
Push — master ( 39bde9...53659e )
by
unknown
02:47
created

EnvCheckMiddleware::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 9
dl 0
loc 23
rs 9.9332
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Nextcloud - Gallery
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Olivier Paroz <[email protected]>
9
 * @author Bernhard Posselt <[email protected]>
10
 * @author Authors of \OCA\Files_Sharing\Helper
11
 *
12
 * @copyright Olivier Paroz 2017
13
 * @copyright Bernhard Posselt 2017
14
 * @copyright Authors of \OCA\Files_Sharing\Helper 2017
15
 */
16
17
namespace OCA\Gallery\Middleware;
18
19
use OCP\Constants;
0 ignored issues
show
Bug introduced by
The type OCP\Constants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use OCP\IRequest;
0 ignored issues
show
Bug introduced by
The type OCP\IRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use OCP\IURLGenerator;
0 ignored issues
show
Bug introduced by
The type OCP\IURLGenerator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use OCP\ISession;
0 ignored issues
show
Bug introduced by
The type OCP\ISession was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use OCP\ILogger;
0 ignored issues
show
Bug introduced by
The type OCP\ILogger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use OCP\Share;
0 ignored issues
show
Bug introduced by
The type OCP\Share was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use OCP\Share\IShare;
0 ignored issues
show
Bug introduced by
The type OCP\Share\IShare was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use OCP\Share\Exceptions\ShareNotFound;
0 ignored issues
show
Bug introduced by
The type OCP\Share\Exceptions\ShareNotFound was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use OCP\Security\IHasher;
0 ignored issues
show
Bug introduced by
The type OCP\Security\IHasher was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
29
use OCP\AppFramework\Http;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use OCP\AppFramework\Utility\IControllerMethodReflector;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Utility...ntrollerMethodReflector was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
32
use OCA\Gallery\Environment\Environment;
33
use OCP\Share\IManager;
0 ignored issues
show
Bug introduced by
The type OCP\Share\IManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
35
/**
36
 * Checks that we have a valid token linked to a valid resource and that the
37
 * user is authorised to access it
38
 *
39
 * Once all checks have been passed, the environment is ready to use
40
 *
41
 * @package OCA\Gallery\Middleware
42
 */
43
class EnvCheckMiddleware extends CheckMiddleware {
44
45
	/** @var IHasher */
46
	private $hasher;
47
	/** @var ISession */
48
	private $session;
49
	/** @var Environment */
50
	private $environment;
51
	/** @var IControllerMethodReflector */
52
	protected $reflector;
53
	/** @var IManager */
54
	protected $shareManager;
55
56
	/***
57
	 * Constructor
58
	 *
59
	 * @param string $appName
60
	 * @param IRequest $request
61
	 * @param IHasher $hasher
62
	 * @param ISession $session
63
	 * @param Environment $environment
64
	 * @param IControllerMethodReflector $reflector
65
	 * @param IURLGenerator $urlGenerator
66
	 * @param ILogger $logger
67
	 * @param IManager $shareManager
68
	 */
69
	public function __construct(
70
		$appName,
71
		IRequest $request,
72
		IHasher $hasher,
73
		ISession $session,
74
		Environment $environment,
75
		IControllerMethodReflector $reflector,
76
		IURLGenerator $urlGenerator,
77
		IManager $shareManager,
78
		ILogger $logger
79
	) {
80
		parent::__construct(
81
			$appName,
82
			$request,
83
			$urlGenerator,
84
			$logger
85
		);
86
87
		$this->hasher = $hasher;
88
		$this->session = $session;
89
		$this->environment = $environment;
90
		$this->reflector = $reflector;
91
		$this->shareManager = $shareManager;
92
	}
93
94
	/**
95
	 * Checks that we have a valid token linked to a valid resource and that the
96
	 * user is authorised to access it
97
	 *
98
	 * Inspects the controller method annotations and if PublicPage is found
99
	 * it checks that we have a token and an optional password giving access to a valid resource.
100
	 * Once that's done, the environment is setup so that our services can find the resources they
101
	 * need.
102
	 *
103
	 * The checks are not performed on "guest" pages and the environment is not setup. Typical
104
	 * guest pages are anonymous error ages
105
	 *
106
	 * @inheritDoc
107
	 */
108
	public function beforeController($controller, $methodName) {
109
		if ($this->reflector->hasAnnotation('Guest')) {
110
			return;
111
		}
112
		$isPublicPage = $this->reflector->hasAnnotation('PublicPage');
113
		if ($isPublicPage) {
114
			$this->validateAndSetTokenBasedEnv();
115
		} else {
116
			$this->environment->setStandardEnv();
117
		}
118
	}
119
120
	/**
121
	 * Checks that we have a token and an optional password giving access to a
122
	 * valid resource. Sets the token based environment after that
123
	 *
124
	 * @throws CheckException
125
	 */
126
	private function validateAndSetTokenBasedEnv() {
127
		$token = $this->request->getParam('token');
128
		if (!$token) {
129
			throw new CheckException(
130
				"Can't access a public resource without a token", Http::STATUS_NOT_FOUND
131
			);
132
		} else {
133
			$share = $this->getShare($token);
134
135
			if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
136
				throw new CheckException(
137
					"Can't access a public resource that is upload only", Http::STATUS_NOT_FOUND
138
				);
139
			}
140
141
			$password = $this->request->getParam('password');
142
			// Let's see if the user needs to provide a password
143
			$this->checkAuthorisation($share, $password);
144
145
			$this->environment->setTokenBasedEnv($share);
146
		}
147
	}
148
149
	/**
150
	 * Validates a token to make sure its linked to a valid resource
151
	 *
152
	 * Uses Share 2.0
153
	 *
154
	 * @fixme setIncognitoMode in 8.1 https://github.com/owncloud/core/pull/12912
155
	 *
156
	 * @param string $token
157
	 *
158
	 * @throws CheckException
159
	 * @return IShare
160
	 */
161
	private function getShare($token) {
162
		// Allows a logged in user to access public links
163
		\OC_User::setIncognitoMode(true);
0 ignored issues
show
Bug introduced by
The type OC_User was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
164
165
		try {
166
			$share = $this->shareManager->getShareByToken($token);
167
		} catch (ShareNotFound $e) {
168
			throw new CheckException($e->getMessage(), Http::STATUS_NOT_FOUND);
169
		}
170
171
		$this->checkShareIsValid($share, $token);
172
		$this->checkItemType($share);
173
174
		return $share;
175
	}
176
177
	/**
178
	 * Makes sure that the token contains all the information that we need
179
	 *
180
	 * @param IShare $share
181
	 * @param string $token
182
	 *
183
	 * @throws CheckException
184
	 */
185
	private function checkShareIsValid($share, $token) {
186
		if ($share->getShareOwner() === null
187
			|| $share->getTarget() === null
188
		) {
189
			$message =
190
				'Passed token seems to be valid, but it does not contain all necessary information . ("'
191
				. $token . '")';
192
			throw new CheckException($message, Http::STATUS_NOT_FOUND);
193
		}
194
	}
195
196
	/**
197
	 * Makes sure an item type was set for that token
198
	 *
199
	 * @param IShare $share
200
	 *
201
	 * @throws CheckException
202
	 */
203
	private function checkItemType($share) {
204
		if ($share->getNodeType() === null) {
205
			$message = 'No item type set for share id: ' . $share->getId();
206
			throw new CheckException($message, Http::STATUS_NOT_FOUND);
207
		}
208
	}
209
210
211
	/**
212
	 * Checks if a password is required or if the one supplied is working
213
	 *
214
	 * @param IShare $share
215
	 * @param string|null $password optional password
216
	 *
217
	 * @throws CheckException
218
	 */
219
	private function checkAuthorisation($share, $password) {
220
		$passwordRequired = $share->getPassword();
221
222
		if (isset($passwordRequired)) {
223
			if ($password !== null) {
224
				$this->authenticate($share, $password);
225
			} else {
226
				$this->checkSession($share);
227
			}
228
		}
229
	}
230
231
	/**
232
	 * Authenticate link item with the given password
233
	 * or with the session if no password was given.
234
	 *
235
	 * @param IShare $share
236
	 * @param string $password
237
	 *
238
	 * @return bool true if authorized, an exception is raised otherwise
239
	 *
240
	 * @throws CheckException
241
	 */
242
	private function authenticate($share, $password) {
243
		if ((int)$share->getShareType() === Share::SHARE_TYPE_LINK) {
244
			$this->checkPassword($share, $password);
245
		} else {
246
			throw new CheckException(
247
				'Unknown share type ' . $share->getShareType() . ' for share id '
248
				. $share->getId(), Http::STATUS_NOT_FOUND
249
			);
250
		}
251
252
		return true;
253
	}
254
255
	/**
256
	 * Validates the given password
257
	 *
258
	 * @fixme @LukasReschke says: Migrate old hashes to new hash format
259
	 * Due to the fact that there is no reasonable functionality to update the password
260
	 * of an existing share no migration is yet performed there.
261
	 * The only possibility is to update the existing share which will result in a new
262
	 * share ID and is a major hack.
263
	 *
264
	 * In the future the migration should be performed once there is a proper method
265
	 * to update the share's password. (for example `$share->updatePassword($password)`
266
	 *
267
	 * @link https://github.com/owncloud/core/issues/10671
268
	 *
269
	 * @param IShare $share
270
	 * @param string $password
271
	 *
272
	 * @throws CheckException
273
	 */
274
	private function checkPassword($share, $password) {
275
		$newHash = '';
276
		if ($this->shareManager->checkPassword($share, $password)) {
277
			// Save item id in session for future requests
278
			$this->session->set('public_link_authenticated', (string)$share->getId());
279
			// @codeCoverageIgnoreStart
280
			if (!empty($newHash)) {
0 ignored issues
show
introduced by
The condition empty($newHash) is always true.
Loading history...
281
				// For future use
282
			}
283
			// @codeCoverageIgnoreEnd
284
		} else {
285
			throw new CheckException("Wrong password", Http::STATUS_UNAUTHORIZED);
286
		}
287
	}
288
289
	/**
290
	 * Makes sure the user is already properly authenticated when a password is required and none
291
	 * was provided
292
	 *
293
	 * @param IShare $share
294
	 *
295
	 * @throws CheckException
296
	 */
297
	private function checkSession($share) {
298
		// Not authenticated ?
299
		if (!$this->session->exists('public_link_authenticated')
300
			|| $this->session->get('public_link_authenticated') !== (string)$share->getId()
301
		) {
302
			throw new CheckException("Missing password", Http::STATUS_UNAUTHORIZED);
303
		}
304
	}
305
306
}
307