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