Completed
Push — master ( ca3aef...5b2d6b )
by Morris
15:49
created

RequestSharedSecret::run()   C

Complexity

Conditions 10
Paths 114

Size

Total Lines 64
Code Lines 39

Duplication

Lines 10
Ratio 15.63 %

Importance

Changes 0
Metric Value
cc 10
eloc 39
nc 114
nop 1
dl 10
loc 64
rs 6.0079
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 *
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
27
namespace OCA\Federation\BackgroundJob;
28
29
30
use GuzzleHttp\Exception\ClientException;
31
use OC\BackgroundJob\JobList;
32
use OC\BackgroundJob\Job;
33
use OCA\Federation\DbHandler;
34
use OCA\Federation\TrustedServers;
35
use OCP\AppFramework\Http;
36
use OCP\AppFramework\Utility\ITimeFactory;
37
use OCP\BackgroundJob\IJobList;
38
use OCP\Http\Client\IClient;
39
use OCP\Http\Client\IClientService;
40
use OCP\ILogger;
41
use OCP\IURLGenerator;
42
use OCP\OCS\IDiscoveryService;
43
44
/**
45
 * Class RequestSharedSecret
46
 *
47
 * Ask remote Nextcloud to request a sharedSecret from this server
48
 *
49
 * @package OCA\Federation\Backgroundjob
50
 */
51
class RequestSharedSecret extends Job {
52
53
	/** @var IClient */
54
	private $httpClient;
55
56
	/** @var IJobList */
57
	private $jobList;
58
59
	/** @var IURLGenerator */
60
	private $urlGenerator;
61
62
	/** @var DbHandler */
63
	private $dbHandler;
64
65
	/** @var TrustedServers */
66
	private $trustedServers;
67
68
	/** @var IDiscoveryService  */
69
	private $ocsDiscoveryService;
70
71
	/** @var ILogger */
72
	private $logger;
73
74
	/** @var ITimeFactory */
75
	private $timeFactory;
76
77
	/** @var bool */
78
	protected $retainJob = false;
79
80
	private $format = '?format=json';
81
82
	private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret';
83
84
	/** @var  int  30 day = 2592000sec */
85
	private $maxLifespan = 2592000;
86
87
	/**
88
	 * RequestSharedSecret constructor.
89
	 *
90
	 * @param IClientService $httpClientService
91
	 * @param IURLGenerator $urlGenerator
92
	 * @param IJobList $jobList
93
	 * @param TrustedServers $trustedServers
94
	 * @param DbHandler $dbHandler
95
	 * @param IDiscoveryService $ocsDiscoveryService
96
	 * @param ILogger $logger
97
	 * @param ITimeFactory $timeFactory
98
	 */
99 View Code Duplication
	public function __construct(
100
		IClientService $httpClientService,
101
		IURLGenerator $urlGenerator,
102
		IJobList $jobList,
103
		TrustedServers $trustedServers,
104
		DbHandler $dbHandler,
105
		IDiscoveryService $ocsDiscoveryService,
106
		ILogger $logger,
107
		ITimeFactory $timeFactory
108
	) {
109
		$this->httpClient = $httpClientService->newClient();
110
		$this->jobList = $jobList;
111
		$this->urlGenerator = $urlGenerator;
112
		$this->dbHandler = $dbHandler;
113
		$this->logger = $logger;
114
		$this->ocsDiscoveryService = $ocsDiscoveryService;
115
		$this->trustedServers = $trustedServers;
116
		$this->timeFactory = $timeFactory;
117
	}
118
119
120
	/**
121
	 * run the job, then remove it from the joblist
122
	 *
123
	 * @param JobList $jobList
124
	 * @param ILogger|null $logger
125
	 */
126 View Code Duplication
	public function execute($jobList, ILogger $logger = null) {
127
		$target = $this->argument['url'];
128
		// only execute if target is still in the list of trusted domains
129
		if ($this->trustedServers->isTrustedServer($target)) {
130
			$this->parentExecute($jobList, $logger);
0 ignored issues
show
Bug introduced by
It seems like $logger defined by parameter $logger on line 126 can be null; however, OCA\Federation\Backgroun...Secret::parentExecute() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
131
		}
132
133
		$jobList->remove($this, $this->argument);
134
135
		if ($this->retainJob) {
136
			$this->reAddJob($this->argument);
137
		}
138
	}
139
140
	/**
141
	 * call execute() method of parent
142
	 *
143
	 * @param JobList $jobList
144
	 * @param ILogger $logger
145
	 */
146
	protected function parentExecute($jobList, $logger) {
147
		parent::execute($jobList, $logger);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (execute() instead of parentExecute()). Are you sure this is correct? If so, you might want to change this to $this->execute().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
148
	}
149
150
	protected function run($argument) {
151
152
		$target = $argument['url'];
153
		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
154
		$currentTime = $this->timeFactory->getTime();
155
		$source = $this->urlGenerator->getAbsoluteURL('/');
156
		$source = rtrim($source, '/');
157
		$token = $argument['token'];
158
159
		// kill job after 30 days of trying
160
		$deadline = $currentTime - $this->maxLifespan;
161 View Code Duplication
		if ($created < $deadline) {
162
			$this->retainJob = false;
163
			$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
164
			return;
165
		}
166
167
		$endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING');
168
		$endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
169
170
		// make sure that we have a well formated url
171
		$url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format;
172
173
		try {
174
			$result = $this->httpClient->post(
175
				$url,
176
				[
177
					'body' => [
178
						'url' => $source,
179
						'token' => $token,
180
					],
181
					'timeout' => 3,
182
					'connect_timeout' => 3,
183
				]
184
			);
185
186
			$status = $result->getStatusCode();
187
188
		} 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...
189
			$status = $e->getCode();
190 View Code Duplication
			if ($status === Http::STATUS_FORBIDDEN) {
191
				$this->logger->info($target . ' refused to ask for a shared secret.', ['app' => 'federation']);
192
			} else {
193
				$this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']);
194
			}
195
		} catch (\Exception $e) {
196
			$status = Http::STATUS_INTERNAL_SERVER_ERROR;
197
			$this->logger->logException($e, ['app' => 'federation']);
198
		}
199
200
		// if we received a unexpected response we try again later
201
		if (
202
			$status !== Http::STATUS_OK
203
			&& $status !== Http::STATUS_FORBIDDEN
204
		) {
205
			$this->retainJob = true;
206
		}
207
208
		if ($status === Http::STATUS_FORBIDDEN) {
209
			// clear token if remote server refuses to ask for shared secret
210
			$this->dbHandler->addToken($target, '');
211
		}
212
213
	}
214
215
	/**
216
	 * re-add background job
217
	 *
218
	 * @param array $argument
219
	 */
220 View Code Duplication
	protected function reAddJob(array $argument) {
221
		$url = $argument['url'];
222
		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
223
		$token = $argument['token'];
224
225
		$this->jobList->add(
226
			RequestSharedSecret::class,
227
			[
228
				'url' => $url,
229
				'token' => $token,
230
				'created' => $created
231
			]
232
		);
233
	}
234
}
235