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

GetSharedSecret::parentExecute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
use GuzzleHttp\Exception\ClientException;
30
use OC\BackgroundJob\JobList;
31
use OC\BackgroundJob\Job;
32
use OCA\Federation\DbHandler;
33
use OCA\Federation\TrustedServers;
34
use OCP\AppFramework\Http;
35
use OCP\AppFramework\Utility\ITimeFactory;
36
use OCP\BackgroundJob\IJobList;
37
use OCP\Http\Client\IClient;
38
use OCP\Http\Client\IClientService;
39
use OCP\Http\Client\IResponse;
40
use OCP\ILogger;
41
use OCP\IURLGenerator;
42
use OCP\OCS\IDiscoveryService;
43
44
/**
45
 * Class GetSharedSecret
46
 *
47
 * request shared secret from remote Nextcloud
48
 *
49
 * @package OCA\Federation\Backgroundjob
50
 */
51
class GetSharedSecret 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 TrustedServers  */
63
	private $trustedServers;
64
65
	/** @var DbHandler */
66
	private $dbHandler;
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/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 ILogger $logger
95
	 * @param DbHandler $dbHandler
96
	 * @param IDiscoveryService $ocsDiscoveryService
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
		ILogger $logger,
105
		DbHandler $dbHandler,
106
		IDiscoveryService $ocsDiscoveryService,
107
		ITimeFactory $timeFactory
108
	) {
109
		$this->logger = $logger;
110
		$this->httpClient = $httpClientService->newClient();
111
		$this->jobList = $jobList;
112
		$this->urlGenerator = $urlGenerator;
113
		$this->dbHandler = $dbHandler;
114
		$this->ocsDiscoveryService = $ocsDiscoveryService;
115
		$this->trustedServers = $trustedServers;
116
		$this->timeFactory = $timeFactory;
117
	}
118
119
	/**
120
	 * run the job, then remove it from the joblist
121
	 *
122
	 * @param JobList $jobList
123
	 * @param ILogger|null $logger
124
	 */
125 View Code Duplication
	public function execute($jobList, ILogger $logger = null) {
126
		$target = $this->argument['url'];
127
		// only execute if target is still in the list of trusted domains
128
		if ($this->trustedServers->isTrustedServer($target)) {
129
			$this->parentExecute($jobList, $logger);
130
		}
131
132
		$jobList->remove($this, $this->argument);
133
134
		if ($this->retainJob) {
135
			$this->reAddJob($this->argument);
136
		}
137
	}
138
139
	/**
140
	 * call execute() method of parent
141
	 *
142
	 * @param JobList $jobList
143
	 * @param ILogger $logger
144
	 */
145
	protected function parentExecute($jobList, $logger = null) {
146
		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...
147
	}
148
149
	protected function run($argument) {
150
		$target = $argument['url'];
151
		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
152
		$currentTime = $this->timeFactory->getTime();
153
		$source = $this->urlGenerator->getAbsoluteURL('/');
154
		$source = rtrim($source, '/');
155
		$token = $argument['token'];
156
157
		// kill job after 30 days of trying
158
		$deadline = $currentTime - $this->maxLifespan;
159 View Code Duplication
		if ($created < $deadline) {
160
			$this->retainJob = false;
161
			$this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE);
162
			return;
163
		}
164
165
		$endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING');
166
		$endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
167
168
		// make sure that we have a well formatted url
169
		$url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format;
170
171
		$result = null;
172
		try {
173
			$result = $this->httpClient->get(
174
				$url,
175
				[
176
					'query' =>
177
						[
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 exchange a shared secret with you.', ['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
		}  else {
207
			// reset token if we received a valid response
208
			$this->dbHandler->addToken($target, '');
209
		}
210
211
		if ($status === Http::STATUS_OK && $result instanceof IResponse) {
212
			$body = $result->getBody();
213
			$result = json_decode($body, true);
214
			if (isset($result['ocs']['data']['sharedSecret'])) {
215
				$this->trustedServers->addSharedSecret(
216
						$target,
217
						$result['ocs']['data']['sharedSecret']
218
				);
219
			} else {
220
				$this->logger->error(
221
						'remote server "' . $target . '"" does not return a valid shared secret',
222
						['app' => 'federation']
223
				);
224
				$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
225
			}
226
		}
227
228
	}
229
230
	/**
231
	 * re-add background job
232
	 *
233
	 * @param array $argument
234
	 */
235 View Code Duplication
	protected function reAddJob(array $argument) {
236
		$url = $argument['url'];
237
		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
238
		$token = $argument['token'];
239
		$this->jobList->add(
240
			GetSharedSecret::class,
241
			[
242
				'url' => $url,
243
				'token' => $token,
244
				'created' => $created
245
			]
246
		);
247
	}
248
}
249