Passed
Push — master ( ad0b67...1846bc )
by Roeland
10:14 queued 10s
created
apps/files_sharing/lib/External/Storage.php 1 patch
Indentation   +378 added lines, -378 removed lines patch added patch discarded remove patch
@@ -45,382 +45,382 @@
 block discarded – undo
45 45
 use OCP\Files\StorageNotAvailableException;
46 46
 
47 47
 class Storage extends DAV implements ISharedStorage, IDisableEncryptionStorage {
48
-	/** @var ICloudId */
49
-	private $cloudId;
50
-	/** @var string */
51
-	private $mountPoint;
52
-	/** @var string */
53
-	private $token;
54
-	/** @var \OCP\ICacheFactory */
55
-	private $memcacheFactory;
56
-	/** @var \OCP\Http\Client\IClientService */
57
-	private $httpClient;
58
-	/** @var bool */
59
-	private $updateChecked = false;
60
-
61
-	/**
62
-	 * @var \OCA\Files_Sharing\External\Manager
63
-	 */
64
-	private $manager;
65
-
66
-	public function __construct($options) {
67
-		$this->memcacheFactory = \OC::$server->getMemCacheFactory();
68
-		$this->httpClient = $options['HttpClientService'];
69
-
70
-		$this->manager = $options['manager'];
71
-		$this->cloudId = $options['cloudId'];
72
-		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
73
-
74
-		list($protocol, $remote) = explode('://', $this->cloudId->getRemote());
75
-		if (strpos($remote, '/')) {
76
-			list($host, $root) = explode('/', $remote, 2);
77
-		} else {
78
-			$host = $remote;
79
-			$root = '';
80
-		}
81
-		$secure = $protocol === 'https';
82
-		$federatedSharingEndpoints = $discoveryService->discover($this->cloudId->getRemote(), 'FEDERATED_SHARING');
83
-		$webDavEndpoint = isset($federatedSharingEndpoints['webdav']) ? $federatedSharingEndpoints['webdav'] : '/public.php/webdav';
84
-		$root = rtrim($root, '/') . $webDavEndpoint;
85
-		$this->mountPoint = $options['mountpoint'];
86
-		$this->token = $options['token'];
87
-
88
-		parent::__construct(array(
89
-			'secure' => $secure,
90
-			'host' => $host,
91
-			'root' => $root,
92
-			'user' => $options['token'],
93
-			'password' => (string)$options['password']
94
-		));
95
-	}
96
-
97
-	public function getWatcher($path = '', $storage = null) {
98
-		if (!$storage) {
99
-			$storage = $this;
100
-		}
101
-		if (!isset($this->watcher)) {
102
-			$this->watcher = new Watcher($storage);
103
-			$this->watcher->setPolicy(\OC\Files\Cache\Watcher::CHECK_ONCE);
104
-		}
105
-		return $this->watcher;
106
-	}
107
-
108
-	public function getRemoteUser() {
109
-		return $this->cloudId->getUser();
110
-	}
111
-
112
-	public function getRemote() {
113
-		return $this->cloudId->getRemote();
114
-	}
115
-
116
-	public function getMountPoint() {
117
-		return $this->mountPoint;
118
-	}
119
-
120
-	public function getToken() {
121
-		return $this->token;
122
-	}
123
-
124
-	public function getPassword() {
125
-		return $this->password;
126
-	}
127
-
128
-	/**
129
-	 * @brief get id of the mount point
130
-	 * @return string
131
-	 */
132
-	public function getId() {
133
-		return 'shared::' . md5($this->token . '@' . $this->getRemote());
134
-	}
135
-
136
-	public function getCache($path = '', $storage = null) {
137
-		if (is_null($this->cache)) {
138
-			$this->cache = new Cache($this, $this->cloudId);
139
-		}
140
-		return $this->cache;
141
-	}
142
-
143
-	/**
144
-	 * @param string $path
145
-	 * @param \OC\Files\Storage\Storage $storage
146
-	 * @return \OCA\Files_Sharing\External\Scanner
147
-	 */
148
-	public function getScanner($path = '', $storage = null) {
149
-		if (!$storage) {
150
-			$storage = $this;
151
-		}
152
-		if (!isset($this->scanner)) {
153
-			$this->scanner = new Scanner($storage);
154
-		}
155
-		return $this->scanner;
156
-	}
157
-
158
-	/**
159
-	 * check if a file or folder has been updated since $time
160
-	 *
161
-	 * @param string $path
162
-	 * @param int $time
163
-	 * @throws \OCP\Files\StorageNotAvailableException
164
-	 * @throws \OCP\Files\StorageInvalidException
165
-	 * @return bool
166
-	 */
167
-	public function hasUpdated($path, $time) {
168
-		// since for owncloud webdav servers we can rely on etag propagation we only need to check the root of the storage
169
-		// because of that we only do one check for the entire storage per request
170
-		if ($this->updateChecked) {
171
-			return false;
172
-		}
173
-		$this->updateChecked = true;
174
-		try {
175
-			return parent::hasUpdated('', $time);
176
-		} catch (StorageInvalidException $e) {
177
-			// check if it needs to be removed
178
-			$this->checkStorageAvailability();
179
-			throw $e;
180
-		} catch (StorageNotAvailableException $e) {
181
-			// check if it needs to be removed or just temp unavailable
182
-			$this->checkStorageAvailability();
183
-			throw $e;
184
-		}
185
-	}
186
-
187
-	public function test() {
188
-		try {
189
-			return parent::test();
190
-		} catch (StorageInvalidException $e) {
191
-			// check if it needs to be removed
192
-			$this->checkStorageAvailability();
193
-			throw $e;
194
-		} catch (StorageNotAvailableException $e) {
195
-			// check if it needs to be removed or just temp unavailable
196
-			$this->checkStorageAvailability();
197
-			throw $e;
198
-		}
199
-	}
200
-
201
-	/**
202
-	 * Check whether this storage is permanently or temporarily
203
-	 * unavailable
204
-	 *
205
-	 * @throws \OCP\Files\StorageNotAvailableException
206
-	 * @throws \OCP\Files\StorageInvalidException
207
-	 */
208
-	public function checkStorageAvailability() {
209
-		// see if we can find out why the share is unavailable
210
-		try {
211
-			$this->getShareInfo();
212
-		} catch (NotFoundException $e) {
213
-			// a 404 can either mean that the share no longer exists or there is no Nextcloud on the remote
214
-			if ($this->testRemote()) {
215
-				// valid Nextcloud instance means that the public share no longer exists
216
-				// since this is permanent (re-sharing the file will create a new token)
217
-				// we remove the invalid storage
218
-				$this->manager->removeShare($this->mountPoint);
219
-				$this->manager->getMountManager()->removeMount($this->mountPoint);
220
-				throw new StorageInvalidException();
221
-			} else {
222
-				// Nextcloud instance is gone, likely to be a temporary server configuration error
223
-				throw new StorageNotAvailableException();
224
-			}
225
-		} catch (ForbiddenException $e) {
226
-			// auth error, remove share for now (provide a dialog in the future)
227
-			$this->manager->removeShare($this->mountPoint);
228
-			$this->manager->getMountManager()->removeMount($this->mountPoint);
229
-			throw new StorageInvalidException();
230
-		} catch (\GuzzleHttp\Exception\ConnectException $e) {
231
-			throw new StorageNotAvailableException();
232
-		} catch (\GuzzleHttp\Exception\RequestException $e) {
233
-			throw new StorageNotAvailableException();
234
-		} catch (\Exception $e) {
235
-			throw $e;
236
-		}
237
-	}
238
-
239
-	public function file_exists($path) {
240
-		if ($path === '') {
241
-			return true;
242
-		} else {
243
-			return parent::file_exists($path);
244
-		}
245
-	}
246
-
247
-	/**
248
-	 * check if the configured remote is a valid federated share provider
249
-	 *
250
-	 * @return bool
251
-	 */
252
-	protected function testRemote() {
253
-		try {
254
-			return $this->testRemoteUrl($this->getRemote() . '/ocs-provider/index.php')
255
-				|| $this->testRemoteUrl($this->getRemote() . '/ocs-provider/')
256
-				|| $this->testRemoteUrl($this->getRemote() . '/status.php');
257
-		} catch (\Exception $e) {
258
-			return false;
259
-		}
260
-	}
261
-
262
-	/**
263
-	 * @param string $url
264
-	 * @return bool
265
-	 */
266
-	private function testRemoteUrl($url) {
267
-		$cache = $this->memcacheFactory->createDistributed('files_sharing_remote_url');
268
-		if($cache->hasKey($url)) {
269
-			return (bool)$cache->get($url);
270
-		}
271
-
272
-		$client = $this->httpClient->newClient();
273
-		try {
274
-			$result = $client->get($url, [
275
-				'timeout' => 10,
276
-				'connect_timeout' => 10,
277
-			])->getBody();
278
-			$data = json_decode($result);
279
-			$returnValue = (is_object($data) && !empty($data->version));
280
-		} catch (ConnectException $e) {
281
-			$returnValue = false;
282
-		} catch (ClientException $e) {
283
-			$returnValue = false;
284
-		} catch (RequestException $e) {
285
-			$returnValue = false;
286
-		}
287
-
288
-		$cache->set($url, $returnValue, 60*60*24);
289
-		return $returnValue;
290
-	}
291
-
292
-	/**
293
-	 * Whether the remote is an ownCloud/Nextcloud, used since some sharing features are not
294
-	 * standardized. Let's use this to detect whether to use it.
295
-	 *
296
-	 * @return bool
297
-	 */
298
-	public function remoteIsOwnCloud() {
299
-		if(defined('PHPUNIT_RUN') || !$this->testRemoteUrl($this->getRemote() . '/status.php')) {
300
-			return false;
301
-		}
302
-		return true;
303
-	}
304
-
305
-	/**
306
-	 * @return mixed
307
-	 * @throws ForbiddenException
308
-	 * @throws NotFoundException
309
-	 * @throws \Exception
310
-	 */
311
-	public function getShareInfo() {
312
-		$remote = $this->getRemote();
313
-		$token = $this->getToken();
314
-		$password = $this->getPassword();
315
-
316
-		// If remote is not an ownCloud do not try to get any share info
317
-		if(!$this->remoteIsOwnCloud()) {
318
-			return ['status' => 'unsupported'];
319
-		}
320
-
321
-		$url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
322
-
323
-		// TODO: DI
324
-		$client = \OC::$server->getHTTPClientService()->newClient();
325
-		try {
326
-			$response = $client->post($url, [
327
-				'body' => ['password' => $password],
328
-				'timeout' => 10,
329
-				'connect_timeout' => 10,
330
-			]);
331
-		} catch (\GuzzleHttp\Exception\RequestException $e) {
332
-			if ($e->getCode() === Http::STATUS_UNAUTHORIZED || $e->getCode() === Http::STATUS_FORBIDDEN) {
333
-				throw new ForbiddenException();
334
-			}
335
-			if ($e->getCode() === Http::STATUS_NOT_FOUND) {
336
-				throw new NotFoundException();
337
-			}
338
-			// throw this to be on the safe side: the share will still be visible
339
-			// in the UI in case the failure is intermittent, and the user will
340
-			// be able to decide whether to remove it if it's really gone
341
-			throw new StorageNotAvailableException();
342
-		}
343
-
344
-		return json_decode($response->getBody(), true);
345
-	}
346
-
347
-	public function getOwner($path) {
348
-		return $this->cloudId->getDisplayId();
349
-	}
350
-
351
-	public function isSharable($path) {
352
-		if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
353
-			return false;
354
-		}
355
-		return ($this->getPermissions($path) & Constants::PERMISSION_SHARE);
356
-	}
357
-
358
-	public function getPermissions($path) {
359
-		$response = $this->propfind($path);
360
-		// old federated sharing permissions
361
-		if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
362
-			$permissions = $response['{http://open-collaboration-services.org/ns}share-permissions'];
363
-		} else if (isset($response['{http://open-cloud-mesh.org/ns}share-permissions'])) {
364
-			// permissions provided by the OCM API
365
-			$permissions = $this->ocmPermissions2ncPermissions($response['{http://open-collaboration-services.org/ns}share-permissions']);
366
-		} else {
367
-			// use default permission if remote server doesn't provide the share permissions
368
-			$permissions = $this->getDefaultPermissions($path);
369
-		}
370
-
371
-		return $permissions;
372
-	}
373
-
374
-	public function needsPartFile() {
375
-		return false;
376
-	}
377
-
378
-	/**
379
-	 * translate OCM Permissions to Nextcloud permissions
380
-	 *
381
-	 * @param string $ocmPermissions json encoded OCM permissions
382
-	 * @param string $path path to file
383
-	 * @return int
384
-	 */
385
-	protected function ocmPermissions2ncPermissions($ocmPermissions, $path) {
386
-		try {
387
-			$ocmPermissions = json_decode($ocmPermissions);
388
-			$ncPermissions = 0;
389
-			foreach($ocmPermissions as $permission) {
390
-				switch (strtolower($permission)) {
391
-					case 'read':
392
-						$ncPermissions += Constants::PERMISSION_READ;
393
-						break;
394
-					case 'write':
395
-						$ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
396
-						break;
397
-					case 'share':
398
-						$ncPermissions += Constants::PERMISSION_SHARE;
399
-						break;
400
-					default:
401
-						throw new \Exception();
402
-				}
403
-			}
404
-		} catch (\Exception $e) {
405
-			$ncPermissions = $this->getDefaultPermissions($path);
406
-		}
407
-
408
-		return $ncPermissions;
409
-	}
410
-
411
-	/**
412
-	 * calculate default permissions in case no permissions are provided
413
-	 *
414
-	 * @param $path
415
-	 * @return int
416
-	 */
417
-	protected function getDefaultPermissions($path) {
418
-		if ($this->is_dir($path)) {
419
-			$permissions = Constants::PERMISSION_ALL;
420
-		} else {
421
-			$permissions = Constants::PERMISSION_ALL & ~Constants::PERMISSION_CREATE;
422
-		}
423
-
424
-		return $permissions;
425
-	}
48
+    /** @var ICloudId */
49
+    private $cloudId;
50
+    /** @var string */
51
+    private $mountPoint;
52
+    /** @var string */
53
+    private $token;
54
+    /** @var \OCP\ICacheFactory */
55
+    private $memcacheFactory;
56
+    /** @var \OCP\Http\Client\IClientService */
57
+    private $httpClient;
58
+    /** @var bool */
59
+    private $updateChecked = false;
60
+
61
+    /**
62
+     * @var \OCA\Files_Sharing\External\Manager
63
+     */
64
+    private $manager;
65
+
66
+    public function __construct($options) {
67
+        $this->memcacheFactory = \OC::$server->getMemCacheFactory();
68
+        $this->httpClient = $options['HttpClientService'];
69
+
70
+        $this->manager = $options['manager'];
71
+        $this->cloudId = $options['cloudId'];
72
+        $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
73
+
74
+        list($protocol, $remote) = explode('://', $this->cloudId->getRemote());
75
+        if (strpos($remote, '/')) {
76
+            list($host, $root) = explode('/', $remote, 2);
77
+        } else {
78
+            $host = $remote;
79
+            $root = '';
80
+        }
81
+        $secure = $protocol === 'https';
82
+        $federatedSharingEndpoints = $discoveryService->discover($this->cloudId->getRemote(), 'FEDERATED_SHARING');
83
+        $webDavEndpoint = isset($federatedSharingEndpoints['webdav']) ? $federatedSharingEndpoints['webdav'] : '/public.php/webdav';
84
+        $root = rtrim($root, '/') . $webDavEndpoint;
85
+        $this->mountPoint = $options['mountpoint'];
86
+        $this->token = $options['token'];
87
+
88
+        parent::__construct(array(
89
+            'secure' => $secure,
90
+            'host' => $host,
91
+            'root' => $root,
92
+            'user' => $options['token'],
93
+            'password' => (string)$options['password']
94
+        ));
95
+    }
96
+
97
+    public function getWatcher($path = '', $storage = null) {
98
+        if (!$storage) {
99
+            $storage = $this;
100
+        }
101
+        if (!isset($this->watcher)) {
102
+            $this->watcher = new Watcher($storage);
103
+            $this->watcher->setPolicy(\OC\Files\Cache\Watcher::CHECK_ONCE);
104
+        }
105
+        return $this->watcher;
106
+    }
107
+
108
+    public function getRemoteUser() {
109
+        return $this->cloudId->getUser();
110
+    }
111
+
112
+    public function getRemote() {
113
+        return $this->cloudId->getRemote();
114
+    }
115
+
116
+    public function getMountPoint() {
117
+        return $this->mountPoint;
118
+    }
119
+
120
+    public function getToken() {
121
+        return $this->token;
122
+    }
123
+
124
+    public function getPassword() {
125
+        return $this->password;
126
+    }
127
+
128
+    /**
129
+     * @brief get id of the mount point
130
+     * @return string
131
+     */
132
+    public function getId() {
133
+        return 'shared::' . md5($this->token . '@' . $this->getRemote());
134
+    }
135
+
136
+    public function getCache($path = '', $storage = null) {
137
+        if (is_null($this->cache)) {
138
+            $this->cache = new Cache($this, $this->cloudId);
139
+        }
140
+        return $this->cache;
141
+    }
142
+
143
+    /**
144
+     * @param string $path
145
+     * @param \OC\Files\Storage\Storage $storage
146
+     * @return \OCA\Files_Sharing\External\Scanner
147
+     */
148
+    public function getScanner($path = '', $storage = null) {
149
+        if (!$storage) {
150
+            $storage = $this;
151
+        }
152
+        if (!isset($this->scanner)) {
153
+            $this->scanner = new Scanner($storage);
154
+        }
155
+        return $this->scanner;
156
+    }
157
+
158
+    /**
159
+     * check if a file or folder has been updated since $time
160
+     *
161
+     * @param string $path
162
+     * @param int $time
163
+     * @throws \OCP\Files\StorageNotAvailableException
164
+     * @throws \OCP\Files\StorageInvalidException
165
+     * @return bool
166
+     */
167
+    public function hasUpdated($path, $time) {
168
+        // since for owncloud webdav servers we can rely on etag propagation we only need to check the root of the storage
169
+        // because of that we only do one check for the entire storage per request
170
+        if ($this->updateChecked) {
171
+            return false;
172
+        }
173
+        $this->updateChecked = true;
174
+        try {
175
+            return parent::hasUpdated('', $time);
176
+        } catch (StorageInvalidException $e) {
177
+            // check if it needs to be removed
178
+            $this->checkStorageAvailability();
179
+            throw $e;
180
+        } catch (StorageNotAvailableException $e) {
181
+            // check if it needs to be removed or just temp unavailable
182
+            $this->checkStorageAvailability();
183
+            throw $e;
184
+        }
185
+    }
186
+
187
+    public function test() {
188
+        try {
189
+            return parent::test();
190
+        } catch (StorageInvalidException $e) {
191
+            // check if it needs to be removed
192
+            $this->checkStorageAvailability();
193
+            throw $e;
194
+        } catch (StorageNotAvailableException $e) {
195
+            // check if it needs to be removed or just temp unavailable
196
+            $this->checkStorageAvailability();
197
+            throw $e;
198
+        }
199
+    }
200
+
201
+    /**
202
+     * Check whether this storage is permanently or temporarily
203
+     * unavailable
204
+     *
205
+     * @throws \OCP\Files\StorageNotAvailableException
206
+     * @throws \OCP\Files\StorageInvalidException
207
+     */
208
+    public function checkStorageAvailability() {
209
+        // see if we can find out why the share is unavailable
210
+        try {
211
+            $this->getShareInfo();
212
+        } catch (NotFoundException $e) {
213
+            // a 404 can either mean that the share no longer exists or there is no Nextcloud on the remote
214
+            if ($this->testRemote()) {
215
+                // valid Nextcloud instance means that the public share no longer exists
216
+                // since this is permanent (re-sharing the file will create a new token)
217
+                // we remove the invalid storage
218
+                $this->manager->removeShare($this->mountPoint);
219
+                $this->manager->getMountManager()->removeMount($this->mountPoint);
220
+                throw new StorageInvalidException();
221
+            } else {
222
+                // Nextcloud instance is gone, likely to be a temporary server configuration error
223
+                throw new StorageNotAvailableException();
224
+            }
225
+        } catch (ForbiddenException $e) {
226
+            // auth error, remove share for now (provide a dialog in the future)
227
+            $this->manager->removeShare($this->mountPoint);
228
+            $this->manager->getMountManager()->removeMount($this->mountPoint);
229
+            throw new StorageInvalidException();
230
+        } catch (\GuzzleHttp\Exception\ConnectException $e) {
231
+            throw new StorageNotAvailableException();
232
+        } catch (\GuzzleHttp\Exception\RequestException $e) {
233
+            throw new StorageNotAvailableException();
234
+        } catch (\Exception $e) {
235
+            throw $e;
236
+        }
237
+    }
238
+
239
+    public function file_exists($path) {
240
+        if ($path === '') {
241
+            return true;
242
+        } else {
243
+            return parent::file_exists($path);
244
+        }
245
+    }
246
+
247
+    /**
248
+     * check if the configured remote is a valid federated share provider
249
+     *
250
+     * @return bool
251
+     */
252
+    protected function testRemote() {
253
+        try {
254
+            return $this->testRemoteUrl($this->getRemote() . '/ocs-provider/index.php')
255
+                || $this->testRemoteUrl($this->getRemote() . '/ocs-provider/')
256
+                || $this->testRemoteUrl($this->getRemote() . '/status.php');
257
+        } catch (\Exception $e) {
258
+            return false;
259
+        }
260
+    }
261
+
262
+    /**
263
+     * @param string $url
264
+     * @return bool
265
+     */
266
+    private function testRemoteUrl($url) {
267
+        $cache = $this->memcacheFactory->createDistributed('files_sharing_remote_url');
268
+        if($cache->hasKey($url)) {
269
+            return (bool)$cache->get($url);
270
+        }
271
+
272
+        $client = $this->httpClient->newClient();
273
+        try {
274
+            $result = $client->get($url, [
275
+                'timeout' => 10,
276
+                'connect_timeout' => 10,
277
+            ])->getBody();
278
+            $data = json_decode($result);
279
+            $returnValue = (is_object($data) && !empty($data->version));
280
+        } catch (ConnectException $e) {
281
+            $returnValue = false;
282
+        } catch (ClientException $e) {
283
+            $returnValue = false;
284
+        } catch (RequestException $e) {
285
+            $returnValue = false;
286
+        }
287
+
288
+        $cache->set($url, $returnValue, 60*60*24);
289
+        return $returnValue;
290
+    }
291
+
292
+    /**
293
+     * Whether the remote is an ownCloud/Nextcloud, used since some sharing features are not
294
+     * standardized. Let's use this to detect whether to use it.
295
+     *
296
+     * @return bool
297
+     */
298
+    public function remoteIsOwnCloud() {
299
+        if(defined('PHPUNIT_RUN') || !$this->testRemoteUrl($this->getRemote() . '/status.php')) {
300
+            return false;
301
+        }
302
+        return true;
303
+    }
304
+
305
+    /**
306
+     * @return mixed
307
+     * @throws ForbiddenException
308
+     * @throws NotFoundException
309
+     * @throws \Exception
310
+     */
311
+    public function getShareInfo() {
312
+        $remote = $this->getRemote();
313
+        $token = $this->getToken();
314
+        $password = $this->getPassword();
315
+
316
+        // If remote is not an ownCloud do not try to get any share info
317
+        if(!$this->remoteIsOwnCloud()) {
318
+            return ['status' => 'unsupported'];
319
+        }
320
+
321
+        $url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
322
+
323
+        // TODO: DI
324
+        $client = \OC::$server->getHTTPClientService()->newClient();
325
+        try {
326
+            $response = $client->post($url, [
327
+                'body' => ['password' => $password],
328
+                'timeout' => 10,
329
+                'connect_timeout' => 10,
330
+            ]);
331
+        } catch (\GuzzleHttp\Exception\RequestException $e) {
332
+            if ($e->getCode() === Http::STATUS_UNAUTHORIZED || $e->getCode() === Http::STATUS_FORBIDDEN) {
333
+                throw new ForbiddenException();
334
+            }
335
+            if ($e->getCode() === Http::STATUS_NOT_FOUND) {
336
+                throw new NotFoundException();
337
+            }
338
+            // throw this to be on the safe side: the share will still be visible
339
+            // in the UI in case the failure is intermittent, and the user will
340
+            // be able to decide whether to remove it if it's really gone
341
+            throw new StorageNotAvailableException();
342
+        }
343
+
344
+        return json_decode($response->getBody(), true);
345
+    }
346
+
347
+    public function getOwner($path) {
348
+        return $this->cloudId->getDisplayId();
349
+    }
350
+
351
+    public function isSharable($path) {
352
+        if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
353
+            return false;
354
+        }
355
+        return ($this->getPermissions($path) & Constants::PERMISSION_SHARE);
356
+    }
357
+
358
+    public function getPermissions($path) {
359
+        $response = $this->propfind($path);
360
+        // old federated sharing permissions
361
+        if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
362
+            $permissions = $response['{http://open-collaboration-services.org/ns}share-permissions'];
363
+        } else if (isset($response['{http://open-cloud-mesh.org/ns}share-permissions'])) {
364
+            // permissions provided by the OCM API
365
+            $permissions = $this->ocmPermissions2ncPermissions($response['{http://open-collaboration-services.org/ns}share-permissions']);
366
+        } else {
367
+            // use default permission if remote server doesn't provide the share permissions
368
+            $permissions = $this->getDefaultPermissions($path);
369
+        }
370
+
371
+        return $permissions;
372
+    }
373
+
374
+    public function needsPartFile() {
375
+        return false;
376
+    }
377
+
378
+    /**
379
+     * translate OCM Permissions to Nextcloud permissions
380
+     *
381
+     * @param string $ocmPermissions json encoded OCM permissions
382
+     * @param string $path path to file
383
+     * @return int
384
+     */
385
+    protected function ocmPermissions2ncPermissions($ocmPermissions, $path) {
386
+        try {
387
+            $ocmPermissions = json_decode($ocmPermissions);
388
+            $ncPermissions = 0;
389
+            foreach($ocmPermissions as $permission) {
390
+                switch (strtolower($permission)) {
391
+                    case 'read':
392
+                        $ncPermissions += Constants::PERMISSION_READ;
393
+                        break;
394
+                    case 'write':
395
+                        $ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
396
+                        break;
397
+                    case 'share':
398
+                        $ncPermissions += Constants::PERMISSION_SHARE;
399
+                        break;
400
+                    default:
401
+                        throw new \Exception();
402
+                }
403
+            }
404
+        } catch (\Exception $e) {
405
+            $ncPermissions = $this->getDefaultPermissions($path);
406
+        }
407
+
408
+        return $ncPermissions;
409
+    }
410
+
411
+    /**
412
+     * calculate default permissions in case no permissions are provided
413
+     *
414
+     * @param $path
415
+     * @return int
416
+     */
417
+    protected function getDefaultPermissions($path) {
418
+        if ($this->is_dir($path)) {
419
+            $permissions = Constants::PERMISSION_ALL;
420
+        } else {
421
+            $permissions = Constants::PERMISSION_ALL & ~Constants::PERMISSION_CREATE;
422
+        }
423
+
424
+        return $permissions;
425
+    }
426 426
 }
Please login to merge, or discard this patch.