Passed
Push — master ( d52ee8...0e6e80 )
by Joas
52:59 queued 30:23
created

TrustedServers   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 69
dl 0
loc 224
rs 10
c 0
b 0
f 0
wmc 20

12 Methods

Rating   Name   Duplication   Size   Complexity  
A addServer() 0 17 2
A __construct() 0 18 1
A getServerStatus() 0 2 1
A removeServer() 0 5 1
A isTrustedServer() 0 2 1
A addSharedSecret() 0 2 1
A getServers() 0 2 1
A setServerStatus() 0 2 1
A isOwnCloudServer() 0 24 3
A checkOwnCloudVersion() 0 9 4
A updateProtocol() 0 9 3
A getSharedSecret() 0 2 1
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Roeland Jago Douma <[email protected]>
11
 * @author Thomas Müller <[email protected]>
12
 *
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
29
namespace OCA\Federation;
30
31
use OC\HintException;
32
use OCA\Federation\BackgroundJob\RequestSharedSecret;
33
use OCP\AppFramework\Http;
34
use OCP\AppFramework\Utility\ITimeFactory;
35
use OCP\BackgroundJob\IJobList;
36
use OCP\Http\Client\IClientService;
37
use OCP\IConfig;
38
use OCP\ILogger;
39
use OCP\Security\ISecureRandom;
40
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
41
use Symfony\Component\EventDispatcher\GenericEvent;
42
43
class TrustedServers {
44
45
	/** after a user list was exchanged at least once successfully */
46
	public const STATUS_OK = 1;
47
	/** waiting for shared secret or initial user list exchange */
48
	public const STATUS_PENDING = 2;
49
	/** something went wrong, misconfigured server, software bug,... user interaction needed */
50
	public const STATUS_FAILURE = 3;
51
	/** remote server revoked access */
52
	public const STATUS_ACCESS_REVOKED = 4;
53
54
	/** @var  dbHandler */
55
	private $dbHandler;
56
57
	/** @var  IClientService */
58
	private $httpClientService;
59
60
	/** @var ILogger */
61
	private $logger;
62
63
	/** @var IJobList */
64
	private $jobList;
65
66
	/** @var ISecureRandom */
67
	private $secureRandom;
68
69
	/** @var IConfig */
70
	private $config;
71
72
	/** @var EventDispatcherInterface */
73
	private $dispatcher;
74
75
	/** @var ITimeFactory */
76
	private $timeFactory;
77
78
	/**
79
	 * @param DbHandler $dbHandler
80
	 * @param IClientService $httpClientService
81
	 * @param ILogger $logger
82
	 * @param IJobList $jobList
83
	 * @param ISecureRandom $secureRandom
84
	 * @param IConfig $config
85
	 * @param EventDispatcherInterface $dispatcher
86
	 * @param ITimeFactory $timeFactory
87
	 */
88
	public function __construct(
89
		DbHandler $dbHandler,
90
		IClientService $httpClientService,
91
		ILogger $logger,
92
		IJobList $jobList,
93
		ISecureRandom $secureRandom,
94
		IConfig $config,
95
		EventDispatcherInterface $dispatcher,
96
		ITimeFactory $timeFactory
97
	) {
98
		$this->dbHandler = $dbHandler;
99
		$this->httpClientService = $httpClientService;
100
		$this->logger = $logger;
101
		$this->jobList = $jobList;
102
		$this->secureRandom = $secureRandom;
103
		$this->config = $config;
104
		$this->dispatcher = $dispatcher;
105
		$this->timeFactory = $timeFactory;
106
	}
107
108
	/**
109
	 * add server to the list of trusted servers
110
	 *
111
	 * @param $url
112
	 * @return int server id
113
	 */
114
	public function addServer($url) {
115
		$url = $this->updateProtocol($url);
116
		$result = $this->dbHandler->addServer($url);
117
		if ($result) {
118
			$token = $this->secureRandom->generate(16);
119
			$this->dbHandler->addToken($url, $token);
120
			$this->jobList->add(
121
				RequestSharedSecret::class,
122
				[
123
					'url' => $url,
124
					'token' => $token,
125
					'created' => $this->timeFactory->getTime()
126
				]
127
			);
128
		}
129
130
		return $result;
131
	}
132
133
	/**
134
	 * get shared secret for the given server
135
	 *
136
	 * @param string $url
137
	 * @return string
138
	 */
139
	public function getSharedSecret($url) {
140
		return $this->dbHandler->getSharedSecret($url);
141
	}
142
143
	/**
144
	 * add shared secret for the given server
145
	 *
146
	 * @param string $url
147
	 * @param $sharedSecret
148
	 */
149
	public function addSharedSecret($url, $sharedSecret) {
150
		$this->dbHandler->addSharedSecret($url, $sharedSecret);
151
	}
152
153
	/**
154
	 * remove server from the list of trusted servers
155
	 *
156
	 * @param int $id
157
	 */
158
	public function removeServer($id) {
159
		$server = $this->dbHandler->getServerById($id);
160
		$this->dbHandler->removeServer($id);
161
		$event = new GenericEvent($server['url_hash']);
162
		$this->dispatcher->dispatch('OCP\Federation\TrustedServerEvent::remove', $event);
0 ignored issues
show
Bug introduced by
'OCP\Federation\TrustedServerEvent::remove' of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

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

162
		$this->dispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Federation\TrustedServerEvent::remove', $event);
Loading history...
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

162
		$this->dispatcher->/** @scrutinizer ignore-call */ 
163
                     dispatch('OCP\Federation\TrustedServerEvent::remove', $event);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
163
	}
164
165
	/**
166
	 * get all trusted servers
167
	 *
168
	 * @return array
169
	 */
170
	public function getServers() {
171
		return $this->dbHandler->getAllServer();
172
	}
173
174
	/**
175
	 * check if given server is a trusted Nextcloud server
176
	 *
177
	 * @param string $url
178
	 * @return bool
179
	 */
180
	public function isTrustedServer($url) {
181
		return $this->dbHandler->serverExists($url);
182
	}
183
184
	/**
185
	 * set server status
186
	 *
187
	 * @param string $url
188
	 * @param int $status
189
	 */
190
	public function setServerStatus($url, $status) {
191
		$this->dbHandler->setServerStatus($url, $status);
192
	}
193
194
	/**
195
	 * @param string $url
196
	 * @return int
197
	 */
198
	public function getServerStatus($url) {
199
		return $this->dbHandler->getServerStatus($url);
200
	}
201
202
	/**
203
	 * check if URL point to a ownCloud/Nextcloud server
204
	 *
205
	 * @param string $url
206
	 * @return bool
207
	 */
208
	public function isOwnCloudServer($url) {
209
		$isValidOwnCloud = false;
210
		$client = $this->httpClientService->newClient();
211
		try {
212
			$result = $client->get(
213
				$url . '/status.php',
214
				[
215
					'timeout' => 3,
216
					'connect_timeout' => 3,
217
				]
218
			);
219
			if ($result->getStatusCode() === Http::STATUS_OK) {
220
				$isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
221
			}
222
		} catch (\Exception $e) {
223
			\OC::$server->getLogger()->logException($e, [
224
				'message' => 'No Nextcloud server.',
225
				'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

225
				'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...
226
				'app' => 'federation',
227
			]);
228
			return false;
229
		}
230
231
		return $isValidOwnCloud;
232
	}
233
234
	/**
235
	 * check if ownCloud version is >= 9.0
236
	 *
237
	 * @param $status
238
	 * @return bool
239
	 * @throws HintException
240
	 */
241
	protected function checkOwnCloudVersion($status) {
242
		$decoded = json_decode($status, true);
243
		if (!empty($decoded) && isset($decoded['version'])) {
244
			if (!version_compare($decoded['version'], '9.0.0', '>=')) {
245
				throw new HintException('Remote server version is too low. 9.0 is required.');
246
			}
247
			return true;
248
		}
249
		return false;
250
	}
251
252
	/**
253
	 * check if the URL contain a protocol, if not add https
254
	 *
255
	 * @param string $url
256
	 * @return string
257
	 */
258
	protected function updateProtocol($url) {
259
		if (
260
			strpos($url, 'https://') === 0
261
			|| strpos($url, 'http://') === 0
262
		) {
263
			return $url;
264
		}
265
266
		return 'https://' . $url;
267
	}
268
}
269