Completed
Push — master ( 828106...487d15 )
by Lukas
14:12 queued 05:48
created

TrustedDomainHelper::isTrustedDomain()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
cc 9
eloc 16
c 4
b 0
f 1
nc 7
nop 1
dl 0
loc 29
rs 4.909
1
<?php
2
/**
3
 * @author Lukas Reschke <[email protected]>
4
 * @author Morris Jobke <[email protected]>
5
 *
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
namespace OC\Security;
24
use OC\AppFramework\Http\Request;
25
use OCP\IConfig;
26
27
/**
28
 * Class TrustedDomain
29
 *
30
 * @package OC\Security
31
 */
32
class TrustedDomainHelper {
33
	/** @var IConfig */
34
	private $config;
35
36
	/**
37
	 * @param IConfig $config
38
	 */
39
	function __construct(IConfig $config) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
40
		$this->config = $config;
41
	}
42
43
	/**
44
	 * Strips a potential port from a domain (in format domain:port)
45
	 * @param string $host
46
	 * @return string $host without appended port
47
	 */
48
	private function getDomainWithoutPort($host) {
49
		$pos = strrpos($host, ':');
50
		if ($pos !== false) {
51
			$port = substr($host, $pos + 1);
52
			if (is_numeric($port)) {
53
				$host = substr($host, 0, $pos);
54
			}
55
		}
56
		return $host;
57
	}
58
59
	/**
60
	 * Checks whether a domain is considered as trusted from the list
61
	 * of trusted domains. If no trusted domains have been configured, returns
62
	 * true.
63
	 * This is used to prevent Host Header Poisoning.
64
	 * @param string $domainWithPort
65
	 * @return bool true if the given domain is trusted or if no trusted domains
66
	 * have been configured
67
	 */
68
	public function isTrustedDomain($domainWithPort) {
69
		$domain = $this->getDomainWithoutPort($domainWithPort);
70
71
		// Read trusted domains from config
72
		$trustedList = $this->config->getSystemValue('trusted_domains', []);
73
		if (!is_array($trustedList)) {
74
			return false;
75
		}
76
77
		// Always allow access from localhost
78
		if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) {
79
			return true;
80
		}
81
		// Reject misformed domains in any case
82
		if (strpos($domain,'-') === 0 || strpos($domain,'..') !== false) {
83
			return false;
84
		}
85
		// Match, allowing for * wildcards
86
		foreach ($trustedList as $trusted) {
87
			if (gettype($trusted) !== 'string') {
88
				break;
89
			}
90
			$regex = '/^' . join('[-\.a-zA-Z0-9]*', array_map(function($v) { return preg_quote($v, '/'); }, explode('*', $trusted))) . '$/';
91
			if (preg_match($regex, $domain) || preg_match($regex, $domainWithPort)) {
92
 				return true;
93
 			}
94
 		}
95
 		return false;
96
	}
97
}
98