Completed
Push — stable10 ( b6f0a0...716adb )
by Lukas
13:48 queued 13:25
created

CheckSetupController::isPhpOutdated()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 2
eloc 4
c 1
b 1
f 0
nc 2
nop 0
dl 0
loc 6
rs 9.4285
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin McCorkell <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OC\Settings\Controller;
28
29
use GuzzleHttp\Exception\ClientException;
30
use OC\AppFramework\Http;
31
use OC\IntegrityCheck\Checker;
32
use OCP\AppFramework\Controller;
33
use OCP\AppFramework\Http\DataDisplayResponse;
34
use OCP\AppFramework\Http\DataResponse;
35
use OCP\AppFramework\Http\RedirectResponse;
36
use OCP\Http\Client\IClientService;
37
use OCP\IConfig;
38
use OCP\IL10N;
39
use OCP\IRequest;
40
use OC_Util;
41
use OCP\IURLGenerator;
42
43
/**
44
 * @package OC\Settings\Controller
45
 */
46
class CheckSetupController extends Controller {
47
	/** @var IConfig */
48
	private $config;
49
	/** @var IClientService */
50
	private $clientService;
51
	/** @var \OC_Util */
52
	private $util;
53
	/** @var IURLGenerator */
54
	private $urlGenerator;
55
	/** @var IL10N */
56
	private $l10n;
57
	/** @var Checker */
58
	private $checker;
59
60
	/**
61
	 * @param string $AppName
62
	 * @param IRequest $request
63
	 * @param IConfig $config
64
	 * @param IClientService $clientService
65
	 * @param IURLGenerator $urlGenerator
66
	 * @param \OC_Util $util
67
	 * @param IL10N $l10n
68
	 * @param Checker $checker
69
	 */
70 View Code Duplication
	public function __construct($AppName,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
71
								IRequest $request,
72
								IConfig $config,
73
								IClientService $clientService,
74
								IURLGenerator $urlGenerator,
75
								\OC_Util $util,
76
								IL10N $l10n,
77
								Checker $checker) {
78
		parent::__construct($AppName, $request);
79
		$this->config = $config;
80
		$this->clientService = $clientService;
81
		$this->util = $util;
82
		$this->urlGenerator = $urlGenerator;
83
		$this->l10n = $l10n;
84
		$this->checker = $checker;
85
	}
86
87
	/**
88
	 * Checks if the ownCloud server can connect to the internet using HTTPS and HTTP
89
	 * @return bool
90
	 */
91
	private function isInternetConnectionWorking() {
92
		if ($this->config->getSystemValue('has_internet_connection', true) === false) {
93
			return false;
94
		}
95
96
		try {
97
			$client = $this->clientService->newClient();
98
			$client->get('https://www.owncloud.org/');
99
			$client->get('http://www.owncloud.org/');
100
			return true;
101
		} catch (\Exception $e) {
102
			return false;
103
		}
104
	}
105
106
	/**
107
	 * Checks whether a local memcache is installed or not
108
	 * @return bool
109
	 */
110
	private function isMemcacheConfigured() {
111
		return $this->config->getSystemValue('memcache.local', null) !== null;
112
	}
113
114
	/**
115
	 * Whether /dev/urandom is available to the PHP controller
116
	 *
117
	 * @return bool
118
	 */
119
	private function isUrandomAvailable() {
120
		if(@file_exists('/dev/urandom')) {
121
			$file = fopen('/dev/urandom', 'rb');
122
			if($file) {
123
				fclose($file);
124
				return true;
125
			}
126
		}
127
128
		return false;
129
	}
130
131
	/**
132
	 * Public for the sake of unit-testing
133
	 *
134
	 * @return array
135
	 */
136
	protected function getCurlVersion() {
137
		return curl_version();
138
	}
139
140
	/**
141
	 * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
142
	 * have multiple bugs which likely lead to problems in combination with
143
	 * functionality required by ownCloud such as SNI.
144
	 *
145
	 * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
146
	 * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
147
	 * @return string
148
	 */
149
	private function isUsedTlsLibOutdated() {
150
		// Appstore is disabled by default in EE
151
		$appStoreDefault = false;
152
		if (\OC_Util::getEditionString() === '') {
153
			$appStoreDefault = true;
154
		}
155
156
		// Don't run check when:
157
		// 1. Server has `has_internet_connection` set to false
158
		// 2. AppStore AND S2S is disabled
159
		if(!$this->config->getSystemValue('has_internet_connection', true)) {
160
			return '';
161
		}
162
		if(!$this->config->getSystemValue('appstoreenabled', $appStoreDefault)
163
			&& $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
164
			&& $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
165
			return '';
166
		}
167
168
		$versionString = $this->getCurlVersion();
169
		if(isset($versionString['ssl_version'])) {
170
			$versionString = $versionString['ssl_version'];
171
		} else {
172
			return '';
173
		}
174
175
		$features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
176
		if(!$this->config->getSystemValue('appstoreenabled', $appStoreDefault)) {
177
			$features = (string)$this->l10n->t('Federated Cloud Sharing');
178
		}
179
180
		// Check if at least OpenSSL after 1.01d or 1.0.2b
181
		if(strpos($versionString, 'OpenSSL/') === 0) {
182
			$majorVersion = substr($versionString, 8, 5);
183
			$patchRelease = substr($versionString, 13, 6);
184
185
			if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
186
				($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
187
				return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['OpenSSL', $versionString, $features]);
188
			}
189
		}
190
191
		// Check if NSS and perform heuristic check
192
		if(strpos($versionString, 'NSS/') === 0) {
193
			try {
194
				$firstClient = $this->clientService->newClient();
195
				$firstClient->get('https://www.owncloud.org/');
196
197
				$secondClient = $this->clientService->newClient();
198
				$secondClient->get('https://owncloud.org/');
199
			} catch (ClientException $e) {
0 ignored issues
show
Bug introduced by
The class GuzzleHttp\Exception\ClientException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
200
				if($e->getResponse()->getStatusCode() === 400) {
201
					return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['NSS', $versionString, $features]);
202
				}
203
			}
204
		}
205
206
		return '';
207
	}
208
209
	/**
210
	 * Whether the version is outdated
211
	 *
212
	 * @return bool
213
	 */
214
	protected function isPhpOutdated() {
215
		if (version_compare(PHP_VERSION, '5.5.0') === -1) {
216
			return true;
217
		}
218
		return false;
219
	}
220
221
	/**
222
	 * Whether the php version is still supported (at time of release)
223
	 * according to: https://secure.php.net/supported-versions.php
224
	 *
225
	 * @return array
226
	 */
227
	private function isPhpSupported() {
228
		return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
229
	}
230
231
	/**
232
	 * Check if the reverse proxy configuration is working as expected
233
	 *
234
	 * @return bool
235
	 */
236
	private function forwardedForHeadersWorking() {
237
		$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
238
		$remoteAddress = $this->request->getRemoteAddress();
239
240
		if (is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
241
			return false;
242
		}
243
244
		// either not enabled or working correctly
245
		return true;
246
	}
247
248
	/**
249
	 * Checks if the correct memcache module for PHP is installed. Only
250
	 * fails if memcached is configured and the working module is not installed.
251
	 *
252
	 * @return bool
253
	 */
254
	private function isCorrectMemcachedPHPModuleInstalled() {
255
		if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
256
			return true;
257
		}
258
259
		// there are two different memcached modules for PHP
260
		// we only support memcached and not memcache
261
		// https://code.google.com/p/memcached/wiki/PHPClientComparison
262
		return !(!extension_loaded('memcached') && extension_loaded('memcache'));
263
	}
264
265
	/**
266
	 * @return RedirectResponse
267
	 */
268
	public function rescanFailedIntegrityCheck() {
269
		$this->checker->runInstanceVerification();
270
		return new RedirectResponse(
271
			$this->urlGenerator->linkToRoute('settings_admin')
272
		);
273
	}
274
275
	/**
276
	 * @NoCSRFRequired
277
	 * @return DataResponse
278
	 */
279
	public function getFailedIntegrityCheckFiles() {
280
		if(!$this->checker->isCodeCheckEnforced()) {
281
			return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
282
		}
283
284
		$completeResults = $this->checker->getResults();
285
286
		if(!empty($completeResults)) {
287
			$formattedTextResponse = 'Technical information
288
=====================
289
The following list covers which files have failed the integrity check. Please read
290
the previous linked documentation to learn more about the errors and how to fix
291
them.
292
293
Results
294
=======
295
';
296
			foreach($completeResults as $context => $contextResult) {
297
				$formattedTextResponse .= "- $context\n";
298
299
				foreach($contextResult as $category => $result) {
300
					$formattedTextResponse .= "\t- $category\n";
301
					if($category !== 'EXCEPTION') {
302
						foreach ($result as $key => $results) {
303
							$formattedTextResponse .= "\t\t- $key\n";
304
						}
305
					} else {
306
						foreach ($result as $key => $results) {
307
							$formattedTextResponse .= "\t\t- $results\n";
308
						}
309
					}
310
311
				}
312
			}
313
314
			$formattedTextResponse .= '
315
Raw output
316
==========
317
';
318
			$formattedTextResponse .= print_r($completeResults, true);
319
		} else {
320
			$formattedTextResponse = 'No errors have been found.';
321
		}
322
323
324
		$response = new DataDisplayResponse(
325
			$formattedTextResponse,
326
			Http::STATUS_OK,
327
			[
328
				'Content-Type' => 'text/plain',
329
			]
330
		);
331
332
		return $response;
333
	}
334
335
	/**
336
	 * @return DataResponse
337
	 */
338
	public function check() {
339
		return new DataResponse(
340
			[
341
				'serverHasInternetConnection' => $this->isInternetConnectionWorking(),
342
				'isMemcacheConfigured' => $this->isMemcacheConfigured(),
343
				'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
344
				'isUrandomAvailable' => $this->isUrandomAvailable(),
345
				'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
346
				'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
347
				'phpSupported' => $this->isPhpSupported(),
348
				'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
349
				'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
350
				'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
351
				'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
352
				'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
353
			]
354
		);
355
	}
356
}
357