Completed
Push — master ( 8b683f...7025f1 )
by Morris
29:10 queued 12:40
created

CloudFederationProviderManager::sendShare()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 33

Duplication

Lines 4
Ratio 12.12 %

Importance

Changes 0
Metric Value
cc 6
nc 13
nop 1
dl 4
loc 33
rs 8.7697
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2018 Bjoern Schiessle <[email protected]>
4
 *
5
 * @license GNU AGPL version 3 or any later version
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as
9
 * published by the Free Software Foundation, either version 3 of the
10
 * License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
23
namespace OC\Federation;
24
25
use OC\AppFramework\Http;
26
use OCP\App\IAppManager;
27
use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
28
use OCP\Federation\ICloudFederationNotification;
29
use OCP\Federation\ICloudFederationProvider;
30
use OCP\Federation\ICloudFederationProviderManager;
31
use OCP\Federation\ICloudFederationShare;
32
use OCP\Federation\ICloudIdManager;
33
use OCP\Http\Client\IClientService;
34
use OCP\ILogger;
35
36
/**
37
 * Class Manager
38
 *
39
 * Manage Cloud Federation Providers
40
 *
41
 * @package OC\Federation
42
 */
43
class CloudFederationProviderManager implements ICloudFederationProviderManager {
44
45
	/** @var array list of available cloud federation providers */
46
	private $cloudFederationProvider;
47
48
	/** @var IAppManager */
49
	private $appManager;
50
51
	/** @var IClientService */
52
	private $httpClientService;
53
54
	/** @var ICloudIdManager */
55
	private $cloudIdManager;
56
57
	/** @var ILogger */
58
	private $logger;
59
60
	/** @var array cache OCM end-points */
61
	private $ocmEndPoints = [];
62
63
	private $supportedAPIVersion = '1.0-proposal1';
64
65
	/**
66
	 * CloudFederationProviderManager constructor.
67
	 *
68
	 * @param IAppManager $appManager
69
	 * @param IClientService $httpClientService
70
	 * @param ICloudIdManager $cloudIdManager
71
	 * @param ILogger $logger
72
	 */
73
	public function __construct(IAppManager $appManager,
74
								IClientService $httpClientService,
75
								ICloudIdManager $cloudIdManager,
76
								ILogger $logger) {
77
		$this->cloudFederationProvider= [];
78
		$this->appManager = $appManager;
79
		$this->httpClientService = $httpClientService;
80
		$this->cloudIdManager = $cloudIdManager;
81
		$this->logger = $logger;
82
	}
83
84
85
	/**
86
	 * Registers an callback function which must return an cloud federation provider
87
	 *
88
	 * @param string $resourceType which resource type does the provider handles
89
	 * @param string $displayName user facing name of the federated share provider
90
	 * @param callable $callback
91
	 */
92
	public function addCloudFederationProvider($resourceType, $displayName, callable $callback) {
93
		$this->cloudFederationProvider[$resourceType] = [
94
			'resourceType' => $resourceType,
95
			'displayName' => $displayName,
96
			'callback' => $callback,
97
		];
98
99
	}
100
101
	/**
102
	 * remove cloud federation provider
103
	 *
104
	 * @param string $providerId
105
	 */
106
	public function removeCloudFederationProvider($providerId) {
107
		unset($this->cloudFederationProvider[$providerId]);
108
	}
109
110
	/**
111
	 * get a list of all cloudFederationProviders
112
	 *
113
	 * @return array [resourceType => ['resourceType' => $resourceType, 'displayName' => $displayName, 'callback' => callback]]
114
	 */
115
	public function getAllCloudFederationProviders() {
116
		return $this->cloudFederationProvider;
117
	}
118
119
	/**
120
	 * get a specific cloud federation provider
121
	 *
122
	 * @param string $resourceType
123
	 * @return ICloudFederationProvider
124
	 * @throws ProviderDoesNotExistsException
125
	 */
126
	public function getCloudFederationProvider($resourceType) {
127
		if (isset($this->cloudFederationProvider[$resourceType])) {
128
			return call_user_func($this->cloudFederationProvider[$resourceType]['callback']);
129
		} else {
130
			throw new ProviderDoesNotExistsException($resourceType);
131
		}
132
	}
133
134
	public function sendShare(ICloudFederationShare $share) {
135
		$cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith());
136
		$ocmEndPoint = $this->getOCMEndPoint($cloudID->getRemote());
137
138
		if (empty($ocmEndPoint)) {
139
			return false;
140
		}
141
142
		$client = $this->httpClientService->newClient();
143
		try {
144
			$response = $client->post($ocmEndPoint . '/shares', [
145
				'body' => $share->getShare(),
146
				'timeout' => 10,
147
				'connect_timeout' => 10,
148
			]);
149
150 View Code Duplication
			if ($response->getStatusCode() === Http::STATUS_CREATED) {
151
				$result = json_decode($response->getBody(), true);
152
				return (is_array($result)) ? $result : [];
153
			}
154
155
		} catch (\Exception $e) {
156
			// if flat re-sharing is not supported by the remote server
157
			// we re-throw the exception and fall back to the old behaviour.
158
			// (flat re-shares has been introduced in Nextcloud 9.1)
159
			if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) {
160
				throw $e;
161
			}
162
		}
163
164
		return false;
165
166
	}
167
168
	/**
169
	 * @param string $url
170
	 * @param ICloudFederationNotification $notification
171
	 * @return mixed
172
	 */
173
	public function sendNotification($url, ICloudFederationNotification $notification) {
174
		$ocmEndPoint = $this->getOCMEndPoint($url);
175
176
		if (empty($ocmEndPoint)) {
177
			return false;
178
		}
179
180
		$client = $this->httpClientService->newClient();
181
		try {
182
			$response = $client->post($ocmEndPoint . '/notifications', [
183
				'body' => $notification->getMessage(),
184
				'timeout' => 10,
185
				'connect_timeout' => 10,
186
			]);
187 View Code Duplication
			if ($response->getStatusCode() === Http::STATUS_CREATED) {
188
				$result = json_decode($response->getBody(), true);
189
				return (is_array($result)) ? $result : [];
190
			}
191
		} catch (\Exception $e) {
192
			// log the error and return false
193
			$this->logger->error('error while sending notification for federated share: ' . $e->getMessage());
194
		}
195
196
		return false;
197
	}
198
199
	/**
200
	 * check if the new cloud federation API is ready to be used
201
	 *
202
	 * @return bool
203
	 */
204
	public function isReady() {
205
		return $this->appManager->isEnabledForUser('cloud_federation_api');
206
	}
207
	/**
208
	 * check if server supports the new OCM api and ask for the correct end-point
209
	 *
210
	 * @param string $url full base URL of the cloud server
211
	 * @return string
212
	 */
213
	protected function getOCMEndPoint($url) {
214
215
		if (isset($this->ocmEndPoints[$url])) {
216
			return $this->ocmEndPoints[$url];
217
		}
218
219
		$client = $this->httpClientService->newClient();
220
		try {
221
			$response = $client->get($url . '/ocm-provider/', ['timeout' => 10, 'connect_timeout' => 10]);
222
		} catch (\Exception $e) {
223
			$this->ocmEndPoints[$url] = '';
224
			return '';
225
		}
226
227
		$result = $response->getBody();
228
		$result = json_decode($result, true);
229
230
		$supportedVersion = isset($result['apiVersion']) && $result['apiVersion'] === $this->supportedAPIVersion;
231
232
		if (isset($result['endPoint']) && $supportedVersion) {
233
			$this->ocmEndPoints[$url] = $result['endPoint'];
234
			return $result['endPoint'];
235
		}
236
237
		$this->ocmEndPoints[$url] = '';
238
		return '';
239
	}
240
241
242
}
243