Passed
Push — master ( bb40e6...385330 )
by Julius
14:49 queued 11s
created
apps/federatedfilesharing/lib/Controller/RequestHandlerController.php 1 patch
Indentation   +400 added lines, -400 removed lines patch added patch discarded remove patch
@@ -50,404 +50,404 @@
 block discarded – undo
50 50
 
51 51
 class RequestHandlerController extends OCSController {
52 52
 
53
-	/** @var FederatedShareProvider */
54
-	private $federatedShareProvider;
55
-
56
-	/** @var IDBConnection */
57
-	private $connection;
58
-
59
-	/** @var Share\IManager */
60
-	private $shareManager;
61
-
62
-	/** @var Notifications */
63
-	private $notifications;
64
-
65
-	/** @var AddressHandler */
66
-	private $addressHandler;
67
-
68
-	/** @var  IUserManager */
69
-	private $userManager;
70
-
71
-	/** @var string */
72
-	private $shareTable = 'share';
73
-
74
-	/** @var ICloudIdManager */
75
-	private $cloudIdManager;
76
-
77
-	/** @var LoggerInterface */
78
-	private $logger;
79
-
80
-	/** @var ICloudFederationFactory */
81
-	private $cloudFederationFactory;
82
-
83
-	/** @var ICloudFederationProviderManager */
84
-	private $cloudFederationProviderManager;
85
-
86
-	public function __construct(string $appName,
87
-								IRequest $request,
88
-								FederatedShareProvider $federatedShareProvider,
89
-								IDBConnection $connection,
90
-								Share\IManager $shareManager,
91
-								Notifications $notifications,
92
-								AddressHandler $addressHandler,
93
-								IUserManager $userManager,
94
-								ICloudIdManager $cloudIdManager,
95
-								LoggerInterface $logger,
96
-								ICloudFederationFactory $cloudFederationFactory,
97
-								ICloudFederationProviderManager $cloudFederationProviderManager
98
-	) {
99
-		parent::__construct($appName, $request);
100
-
101
-		$this->federatedShareProvider = $federatedShareProvider;
102
-		$this->connection = $connection;
103
-		$this->shareManager = $shareManager;
104
-		$this->notifications = $notifications;
105
-		$this->addressHandler = $addressHandler;
106
-		$this->userManager = $userManager;
107
-		$this->cloudIdManager = $cloudIdManager;
108
-		$this->logger = $logger;
109
-		$this->cloudFederationFactory = $cloudFederationFactory;
110
-		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
111
-	}
112
-
113
-	/**
114
-	 * @NoCSRFRequired
115
-	 * @PublicPage
116
-	 *
117
-	 * create a new share
118
-	 *
119
-	 * @return Http\DataResponse
120
-	 * @throws OCSException
121
-	 */
122
-	public function createShare() {
123
-		$remote = isset($_POST['remote']) ? $_POST['remote'] : null;
124
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
125
-		$name = isset($_POST['name']) ? $_POST['name'] : null;
126
-		$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
127
-		$sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
128
-		$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
129
-		$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
130
-		$sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
131
-		$ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
132
-
133
-		if ($ownerFederatedId === null) {
134
-			$ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
135
-		}
136
-		// if the owner of the share and the initiator are the same user
137
-		// we also complete the federated share ID for the initiator
138
-		if ($sharedByFederatedId === null && $owner === $sharedBy) {
139
-			$sharedByFederatedId = $ownerFederatedId;
140
-		}
141
-
142
-		$share = $this->cloudFederationFactory->getCloudFederationShare(
143
-			$shareWith,
144
-			$name,
145
-			'',
146
-			$remoteId,
147
-			$ownerFederatedId,
148
-			$owner,
149
-			$sharedByFederatedId,
150
-			$sharedBy,
151
-			$token,
152
-			'user',
153
-			'file'
154
-		);
155
-
156
-		try {
157
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
158
-			$provider->shareReceived($share);
159
-		} catch (ProviderDoesNotExistsException $e) {
160
-			throw new OCSException('Server does not support federated cloud sharing', 503);
161
-		} catch (ProviderCouldNotAddShareException $e) {
162
-			throw new OCSException($e->getMessage(), 400);
163
-		} catch (\Exception $e) {
164
-			throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
165
-		}
166
-
167
-		return new Http\DataResponse();
168
-	}
169
-
170
-	/**
171
-	 * @NoCSRFRequired
172
-	 * @PublicPage
173
-	 *
174
-	 * create re-share on behalf of another user
175
-	 *
176
-	 * @param int $id
177
-	 * @return Http\DataResponse
178
-	 * @throws OCSBadRequestException
179
-	 * @throws OCSException
180
-	 * @throws OCSForbiddenException
181
-	 */
182
-	public function reShare($id) {
183
-		$token = $this->request->getParam('token', null);
184
-		$shareWith = $this->request->getParam('shareWith', null);
185
-		$permission = (int)$this->request->getParam('permission', null);
186
-		$remoteId = (int)$this->request->getParam('remoteId', null);
187
-
188
-		if ($id === null ||
189
-			$token === null ||
190
-			$shareWith === null ||
191
-			$permission === null ||
192
-			$remoteId === null
193
-		) {
194
-			throw new OCSBadRequestException();
195
-		}
196
-
197
-		$notification = [
198
-			'sharedSecret' => $token,
199
-			'shareWith' => $shareWith,
200
-			'senderId' => $remoteId,
201
-			'message' => 'Recipient of a share ask the owner to reshare the file'
202
-		];
203
-
204
-		try {
205
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
206
-			[$newToken, $localId] = $provider->notificationReceived('REQUEST_RESHARE', $id, $notification);
207
-			return new Http\DataResponse([
208
-				'token' => $newToken,
209
-				'remoteId' => $localId
210
-			]);
211
-		} catch (ProviderDoesNotExistsException $e) {
212
-			throw new OCSException('Server does not support federated cloud sharing', 503);
213
-		} catch (ShareNotFound $e) {
214
-			$this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
215
-		} catch (\Exception $e) {
216
-			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
217
-		}
218
-
219
-		throw new OCSBadRequestException();
220
-	}
221
-
222
-
223
-	/**
224
-	 * @NoCSRFRequired
225
-	 * @PublicPage
226
-	 *
227
-	 * accept server-to-server share
228
-	 *
229
-	 * @param int $id
230
-	 * @return Http\DataResponse
231
-	 * @throws OCSException
232
-	 * @throws ShareNotFound
233
-	 * @throws \OCP\HintException
234
-	 */
235
-	public function acceptShare($id) {
236
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
237
-
238
-		$notification = [
239
-			'sharedSecret' => $token,
240
-			'message' => 'Recipient accept the share'
241
-		];
242
-
243
-		try {
244
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
245
-			$provider->notificationReceived('SHARE_ACCEPTED', $id, $notification);
246
-		} catch (ProviderDoesNotExistsException $e) {
247
-			throw new OCSException('Server does not support federated cloud sharing', 503);
248
-		} catch (ShareNotFound $e) {
249
-			$this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
250
-		} catch (\Exception $e) {
251
-			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
252
-		}
253
-
254
-		return new Http\DataResponse();
255
-	}
256
-
257
-	/**
258
-	 * @NoCSRFRequired
259
-	 * @PublicPage
260
-	 *
261
-	 * decline server-to-server share
262
-	 *
263
-	 * @param int $id
264
-	 * @return Http\DataResponse
265
-	 * @throws OCSException
266
-	 */
267
-	public function declineShare($id) {
268
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
269
-
270
-		$notification = [
271
-			'sharedSecret' => $token,
272
-			'message' => 'Recipient declined the share'
273
-		];
274
-
275
-		try {
276
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
277
-			$provider->notificationReceived('SHARE_DECLINED', $id, $notification);
278
-		} catch (ProviderDoesNotExistsException $e) {
279
-			throw new OCSException('Server does not support federated cloud sharing', 503);
280
-		} catch (ShareNotFound $e) {
281
-			$this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
282
-		} catch (\Exception $e) {
283
-			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
284
-		}
285
-
286
-		return new Http\DataResponse();
287
-	}
288
-
289
-	/**
290
-	 * @NoCSRFRequired
291
-	 * @PublicPage
292
-	 *
293
-	 * remove server-to-server share if it was unshared by the owner
294
-	 *
295
-	 * @param int $id
296
-	 * @return Http\DataResponse
297
-	 * @throws OCSException
298
-	 */
299
-	public function unshare($id) {
300
-		if (!$this->isS2SEnabled()) {
301
-			throw new OCSException('Server does not support federated cloud sharing', 503);
302
-		}
303
-
304
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
305
-
306
-		try {
307
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
308
-			$notification = ['sharedSecret' => $token];
309
-			$provider->notificationReceived('SHARE_UNSHARED', $id, $notification);
310
-		} catch (\Exception $e) {
311
-			$this->logger->debug('processing unshare notification failed: ' . $e->getMessage(), ['exception' => $e]);
312
-		}
313
-
314
-		return new Http\DataResponse();
315
-	}
316
-
317
-	private function cleanupRemote($remote) {
318
-		$remote = substr($remote, strpos($remote, '://') + 3);
319
-
320
-		return rtrim($remote, '/');
321
-	}
322
-
323
-
324
-	/**
325
-	 * @NoCSRFRequired
326
-	 * @PublicPage
327
-	 *
328
-	 * federated share was revoked, either by the owner or the re-sharer
329
-	 *
330
-	 * @param int $id
331
-	 * @return Http\DataResponse
332
-	 * @throws OCSBadRequestException
333
-	 */
334
-	public function revoke($id) {
335
-		$token = $this->request->getParam('token');
336
-
337
-		try {
338
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
339
-			$notification = ['sharedSecret' => $token];
340
-			$provider->notificationReceived('RESHARE_UNDO', $id, $notification);
341
-			return new Http\DataResponse();
342
-		} catch (\Exception $e) {
343
-			throw new OCSBadRequestException();
344
-		}
345
-	}
346
-
347
-	/**
348
-	 * check if server-to-server sharing is enabled
349
-	 *
350
-	 * @param bool $incoming
351
-	 * @return bool
352
-	 */
353
-	private function isS2SEnabled($incoming = false) {
354
-		$result = \OCP\App::isEnabled('files_sharing');
355
-
356
-		if ($incoming) {
357
-			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
358
-		} else {
359
-			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
360
-		}
361
-
362
-		return $result;
363
-	}
364
-
365
-	/**
366
-	 * @NoCSRFRequired
367
-	 * @PublicPage
368
-	 *
369
-	 * update share information to keep federated re-shares in sync
370
-	 *
371
-	 * @param int $id
372
-	 * @return Http\DataResponse
373
-	 * @throws OCSBadRequestException
374
-	 */
375
-	public function updatePermissions($id) {
376
-		$token = $this->request->getParam('token', null);
377
-		$ncPermissions = $this->request->getParam('permissions', null);
378
-
379
-		try {
380
-			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
381
-			$ocmPermissions = $this->ncPermissions2ocmPermissions((int)$ncPermissions);
382
-			$notification = ['sharedSecret' => $token, 'permission' => $ocmPermissions];
383
-			$provider->notificationReceived('RESHARE_CHANGE_PERMISSION', $id, $notification);
384
-		} catch (\Exception $e) {
385
-			$this->logger->debug($e->getMessage(), ['exception' => $e]);
386
-			throw new OCSBadRequestException();
387
-		}
388
-
389
-		return new Http\DataResponse();
390
-	}
391
-
392
-	/**
393
-	 * translate Nextcloud permissions to OCM Permissions
394
-	 *
395
-	 * @param $ncPermissions
396
-	 * @return array
397
-	 */
398
-	protected function ncPermissions2ocmPermissions($ncPermissions) {
399
-		$ocmPermissions = [];
400
-
401
-		if ($ncPermissions & Constants::PERMISSION_SHARE) {
402
-			$ocmPermissions[] = 'share';
403
-		}
404
-
405
-		if ($ncPermissions & Constants::PERMISSION_READ) {
406
-			$ocmPermissions[] = 'read';
407
-		}
408
-
409
-		if (($ncPermissions & Constants::PERMISSION_CREATE) ||
410
-			($ncPermissions & Constants::PERMISSION_UPDATE)) {
411
-			$ocmPermissions[] = 'write';
412
-		}
413
-
414
-		return $ocmPermissions;
415
-	}
416
-
417
-	/**
418
-	 * @NoCSRFRequired
419
-	 * @PublicPage
420
-	 *
421
-	 * change the owner of a server-to-server share
422
-	 *
423
-	 * @param int $id
424
-	 * @return Http\DataResponse
425
-	 * @throws \InvalidArgumentException
426
-	 * @throws OCSException
427
-	 */
428
-	public function move($id) {
429
-		if (!$this->isS2SEnabled()) {
430
-			throw new OCSException('Server does not support federated cloud sharing', 503);
431
-		}
432
-
433
-		$token = $this->request->getParam('token');
434
-		$remote = $this->request->getParam('remote');
435
-		$newRemoteId = $this->request->getParam('remote_id', $id);
436
-		$cloudId = $this->cloudIdManager->resolveCloudId($remote);
437
-
438
-		$qb = $this->connection->getQueryBuilder();
439
-		$query = $qb->update('share_external')
440
-			->set('remote', $qb->createNamedParameter($cloudId->getRemote()))
441
-			->set('owner', $qb->createNamedParameter($cloudId->getUser()))
442
-			->set('remote_id', $qb->createNamedParameter($newRemoteId))
443
-			->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
444
-			->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
445
-		$affected = $query->executeStatement();
446
-
447
-		if ($affected > 0) {
448
-			return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
449
-		} else {
450
-			throw new OCSBadRequestException('Share not found or token invalid');
451
-		}
452
-	}
53
+    /** @var FederatedShareProvider */
54
+    private $federatedShareProvider;
55
+
56
+    /** @var IDBConnection */
57
+    private $connection;
58
+
59
+    /** @var Share\IManager */
60
+    private $shareManager;
61
+
62
+    /** @var Notifications */
63
+    private $notifications;
64
+
65
+    /** @var AddressHandler */
66
+    private $addressHandler;
67
+
68
+    /** @var  IUserManager */
69
+    private $userManager;
70
+
71
+    /** @var string */
72
+    private $shareTable = 'share';
73
+
74
+    /** @var ICloudIdManager */
75
+    private $cloudIdManager;
76
+
77
+    /** @var LoggerInterface */
78
+    private $logger;
79
+
80
+    /** @var ICloudFederationFactory */
81
+    private $cloudFederationFactory;
82
+
83
+    /** @var ICloudFederationProviderManager */
84
+    private $cloudFederationProviderManager;
85
+
86
+    public function __construct(string $appName,
87
+                                IRequest $request,
88
+                                FederatedShareProvider $federatedShareProvider,
89
+                                IDBConnection $connection,
90
+                                Share\IManager $shareManager,
91
+                                Notifications $notifications,
92
+                                AddressHandler $addressHandler,
93
+                                IUserManager $userManager,
94
+                                ICloudIdManager $cloudIdManager,
95
+                                LoggerInterface $logger,
96
+                                ICloudFederationFactory $cloudFederationFactory,
97
+                                ICloudFederationProviderManager $cloudFederationProviderManager
98
+    ) {
99
+        parent::__construct($appName, $request);
100
+
101
+        $this->federatedShareProvider = $federatedShareProvider;
102
+        $this->connection = $connection;
103
+        $this->shareManager = $shareManager;
104
+        $this->notifications = $notifications;
105
+        $this->addressHandler = $addressHandler;
106
+        $this->userManager = $userManager;
107
+        $this->cloudIdManager = $cloudIdManager;
108
+        $this->logger = $logger;
109
+        $this->cloudFederationFactory = $cloudFederationFactory;
110
+        $this->cloudFederationProviderManager = $cloudFederationProviderManager;
111
+    }
112
+
113
+    /**
114
+     * @NoCSRFRequired
115
+     * @PublicPage
116
+     *
117
+     * create a new share
118
+     *
119
+     * @return Http\DataResponse
120
+     * @throws OCSException
121
+     */
122
+    public function createShare() {
123
+        $remote = isset($_POST['remote']) ? $_POST['remote'] : null;
124
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
125
+        $name = isset($_POST['name']) ? $_POST['name'] : null;
126
+        $owner = isset($_POST['owner']) ? $_POST['owner'] : null;
127
+        $sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
128
+        $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
129
+        $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
130
+        $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
131
+        $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
132
+
133
+        if ($ownerFederatedId === null) {
134
+            $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
135
+        }
136
+        // if the owner of the share and the initiator are the same user
137
+        // we also complete the federated share ID for the initiator
138
+        if ($sharedByFederatedId === null && $owner === $sharedBy) {
139
+            $sharedByFederatedId = $ownerFederatedId;
140
+        }
141
+
142
+        $share = $this->cloudFederationFactory->getCloudFederationShare(
143
+            $shareWith,
144
+            $name,
145
+            '',
146
+            $remoteId,
147
+            $ownerFederatedId,
148
+            $owner,
149
+            $sharedByFederatedId,
150
+            $sharedBy,
151
+            $token,
152
+            'user',
153
+            'file'
154
+        );
155
+
156
+        try {
157
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
158
+            $provider->shareReceived($share);
159
+        } catch (ProviderDoesNotExistsException $e) {
160
+            throw new OCSException('Server does not support federated cloud sharing', 503);
161
+        } catch (ProviderCouldNotAddShareException $e) {
162
+            throw new OCSException($e->getMessage(), 400);
163
+        } catch (\Exception $e) {
164
+            throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
165
+        }
166
+
167
+        return new Http\DataResponse();
168
+    }
169
+
170
+    /**
171
+     * @NoCSRFRequired
172
+     * @PublicPage
173
+     *
174
+     * create re-share on behalf of another user
175
+     *
176
+     * @param int $id
177
+     * @return Http\DataResponse
178
+     * @throws OCSBadRequestException
179
+     * @throws OCSException
180
+     * @throws OCSForbiddenException
181
+     */
182
+    public function reShare($id) {
183
+        $token = $this->request->getParam('token', null);
184
+        $shareWith = $this->request->getParam('shareWith', null);
185
+        $permission = (int)$this->request->getParam('permission', null);
186
+        $remoteId = (int)$this->request->getParam('remoteId', null);
187
+
188
+        if ($id === null ||
189
+            $token === null ||
190
+            $shareWith === null ||
191
+            $permission === null ||
192
+            $remoteId === null
193
+        ) {
194
+            throw new OCSBadRequestException();
195
+        }
196
+
197
+        $notification = [
198
+            'sharedSecret' => $token,
199
+            'shareWith' => $shareWith,
200
+            'senderId' => $remoteId,
201
+            'message' => 'Recipient of a share ask the owner to reshare the file'
202
+        ];
203
+
204
+        try {
205
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
206
+            [$newToken, $localId] = $provider->notificationReceived('REQUEST_RESHARE', $id, $notification);
207
+            return new Http\DataResponse([
208
+                'token' => $newToken,
209
+                'remoteId' => $localId
210
+            ]);
211
+        } catch (ProviderDoesNotExistsException $e) {
212
+            throw new OCSException('Server does not support federated cloud sharing', 503);
213
+        } catch (ShareNotFound $e) {
214
+            $this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
215
+        } catch (\Exception $e) {
216
+            $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
217
+        }
218
+
219
+        throw new OCSBadRequestException();
220
+    }
221
+
222
+
223
+    /**
224
+     * @NoCSRFRequired
225
+     * @PublicPage
226
+     *
227
+     * accept server-to-server share
228
+     *
229
+     * @param int $id
230
+     * @return Http\DataResponse
231
+     * @throws OCSException
232
+     * @throws ShareNotFound
233
+     * @throws \OCP\HintException
234
+     */
235
+    public function acceptShare($id) {
236
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
237
+
238
+        $notification = [
239
+            'sharedSecret' => $token,
240
+            'message' => 'Recipient accept the share'
241
+        ];
242
+
243
+        try {
244
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
245
+            $provider->notificationReceived('SHARE_ACCEPTED', $id, $notification);
246
+        } catch (ProviderDoesNotExistsException $e) {
247
+            throw new OCSException('Server does not support federated cloud sharing', 503);
248
+        } catch (ShareNotFound $e) {
249
+            $this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
250
+        } catch (\Exception $e) {
251
+            $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
252
+        }
253
+
254
+        return new Http\DataResponse();
255
+    }
256
+
257
+    /**
258
+     * @NoCSRFRequired
259
+     * @PublicPage
260
+     *
261
+     * decline server-to-server share
262
+     *
263
+     * @param int $id
264
+     * @return Http\DataResponse
265
+     * @throws OCSException
266
+     */
267
+    public function declineShare($id) {
268
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
269
+
270
+        $notification = [
271
+            'sharedSecret' => $token,
272
+            'message' => 'Recipient declined the share'
273
+        ];
274
+
275
+        try {
276
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
277
+            $provider->notificationReceived('SHARE_DECLINED', $id, $notification);
278
+        } catch (ProviderDoesNotExistsException $e) {
279
+            throw new OCSException('Server does not support federated cloud sharing', 503);
280
+        } catch (ShareNotFound $e) {
281
+            $this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
282
+        } catch (\Exception $e) {
283
+            $this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
284
+        }
285
+
286
+        return new Http\DataResponse();
287
+    }
288
+
289
+    /**
290
+     * @NoCSRFRequired
291
+     * @PublicPage
292
+     *
293
+     * remove server-to-server share if it was unshared by the owner
294
+     *
295
+     * @param int $id
296
+     * @return Http\DataResponse
297
+     * @throws OCSException
298
+     */
299
+    public function unshare($id) {
300
+        if (!$this->isS2SEnabled()) {
301
+            throw new OCSException('Server does not support federated cloud sharing', 503);
302
+        }
303
+
304
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
305
+
306
+        try {
307
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
308
+            $notification = ['sharedSecret' => $token];
309
+            $provider->notificationReceived('SHARE_UNSHARED', $id, $notification);
310
+        } catch (\Exception $e) {
311
+            $this->logger->debug('processing unshare notification failed: ' . $e->getMessage(), ['exception' => $e]);
312
+        }
313
+
314
+        return new Http\DataResponse();
315
+    }
316
+
317
+    private function cleanupRemote($remote) {
318
+        $remote = substr($remote, strpos($remote, '://') + 3);
319
+
320
+        return rtrim($remote, '/');
321
+    }
322
+
323
+
324
+    /**
325
+     * @NoCSRFRequired
326
+     * @PublicPage
327
+     *
328
+     * federated share was revoked, either by the owner or the re-sharer
329
+     *
330
+     * @param int $id
331
+     * @return Http\DataResponse
332
+     * @throws OCSBadRequestException
333
+     */
334
+    public function revoke($id) {
335
+        $token = $this->request->getParam('token');
336
+
337
+        try {
338
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
339
+            $notification = ['sharedSecret' => $token];
340
+            $provider->notificationReceived('RESHARE_UNDO', $id, $notification);
341
+            return new Http\DataResponse();
342
+        } catch (\Exception $e) {
343
+            throw new OCSBadRequestException();
344
+        }
345
+    }
346
+
347
+    /**
348
+     * check if server-to-server sharing is enabled
349
+     *
350
+     * @param bool $incoming
351
+     * @return bool
352
+     */
353
+    private function isS2SEnabled($incoming = false) {
354
+        $result = \OCP\App::isEnabled('files_sharing');
355
+
356
+        if ($incoming) {
357
+            $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
358
+        } else {
359
+            $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
360
+        }
361
+
362
+        return $result;
363
+    }
364
+
365
+    /**
366
+     * @NoCSRFRequired
367
+     * @PublicPage
368
+     *
369
+     * update share information to keep federated re-shares in sync
370
+     *
371
+     * @param int $id
372
+     * @return Http\DataResponse
373
+     * @throws OCSBadRequestException
374
+     */
375
+    public function updatePermissions($id) {
376
+        $token = $this->request->getParam('token', null);
377
+        $ncPermissions = $this->request->getParam('permissions', null);
378
+
379
+        try {
380
+            $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
381
+            $ocmPermissions = $this->ncPermissions2ocmPermissions((int)$ncPermissions);
382
+            $notification = ['sharedSecret' => $token, 'permission' => $ocmPermissions];
383
+            $provider->notificationReceived('RESHARE_CHANGE_PERMISSION', $id, $notification);
384
+        } catch (\Exception $e) {
385
+            $this->logger->debug($e->getMessage(), ['exception' => $e]);
386
+            throw new OCSBadRequestException();
387
+        }
388
+
389
+        return new Http\DataResponse();
390
+    }
391
+
392
+    /**
393
+     * translate Nextcloud permissions to OCM Permissions
394
+     *
395
+     * @param $ncPermissions
396
+     * @return array
397
+     */
398
+    protected function ncPermissions2ocmPermissions($ncPermissions) {
399
+        $ocmPermissions = [];
400
+
401
+        if ($ncPermissions & Constants::PERMISSION_SHARE) {
402
+            $ocmPermissions[] = 'share';
403
+        }
404
+
405
+        if ($ncPermissions & Constants::PERMISSION_READ) {
406
+            $ocmPermissions[] = 'read';
407
+        }
408
+
409
+        if (($ncPermissions & Constants::PERMISSION_CREATE) ||
410
+            ($ncPermissions & Constants::PERMISSION_UPDATE)) {
411
+            $ocmPermissions[] = 'write';
412
+        }
413
+
414
+        return $ocmPermissions;
415
+    }
416
+
417
+    /**
418
+     * @NoCSRFRequired
419
+     * @PublicPage
420
+     *
421
+     * change the owner of a server-to-server share
422
+     *
423
+     * @param int $id
424
+     * @return Http\DataResponse
425
+     * @throws \InvalidArgumentException
426
+     * @throws OCSException
427
+     */
428
+    public function move($id) {
429
+        if (!$this->isS2SEnabled()) {
430
+            throw new OCSException('Server does not support federated cloud sharing', 503);
431
+        }
432
+
433
+        $token = $this->request->getParam('token');
434
+        $remote = $this->request->getParam('remote');
435
+        $newRemoteId = $this->request->getParam('remote_id', $id);
436
+        $cloudId = $this->cloudIdManager->resolveCloudId($remote);
437
+
438
+        $qb = $this->connection->getQueryBuilder();
439
+        $query = $qb->update('share_external')
440
+            ->set('remote', $qb->createNamedParameter($cloudId->getRemote()))
441
+            ->set('owner', $qb->createNamedParameter($cloudId->getUser()))
442
+            ->set('remote_id', $qb->createNamedParameter($newRemoteId))
443
+            ->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
444
+            ->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
445
+        $affected = $query->executeStatement();
446
+
447
+        if ($affected > 0) {
448
+            return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
449
+        } else {
450
+            throw new OCSBadRequestException('Share not found or token invalid');
451
+        }
452
+    }
453 453
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/Notifications.php 1 patch
Indentation   +429 added lines, -429 removed lines patch added patch discarded remove patch
@@ -38,433 +38,433 @@
 block discarded – undo
38 38
 use OCP\OCS\IDiscoveryService;
39 39
 
40 40
 class Notifications {
41
-	public const RESPONSE_FORMAT = 'json'; // default response format for ocs calls
42
-
43
-	/** @var AddressHandler */
44
-	private $addressHandler;
45
-
46
-	/** @var IClientService */
47
-	private $httpClientService;
48
-
49
-	/** @var IDiscoveryService */
50
-	private $discoveryService;
51
-
52
-	/** @var IJobList  */
53
-	private $jobList;
54
-
55
-	/** @var ICloudFederationProviderManager */
56
-	private $federationProviderManager;
57
-
58
-	/** @var ICloudFederationFactory */
59
-	private $cloudFederationFactory;
60
-
61
-	/** @var IEventDispatcher */
62
-	private $eventDispatcher;
63
-
64
-	/** @var ILogger */
65
-	private $logger;
66
-
67
-	public function __construct(
68
-		AddressHandler $addressHandler,
69
-		IClientService $httpClientService,
70
-		IDiscoveryService $discoveryService,
71
-		ILogger $logger,
72
-		IJobList $jobList,
73
-		ICloudFederationProviderManager $federationProviderManager,
74
-		ICloudFederationFactory $cloudFederationFactory,
75
-		IEventDispatcher $eventDispatcher
76
-	) {
77
-		$this->addressHandler = $addressHandler;
78
-		$this->httpClientService = $httpClientService;
79
-		$this->discoveryService = $discoveryService;
80
-		$this->jobList = $jobList;
81
-		$this->logger = $logger;
82
-		$this->federationProviderManager = $federationProviderManager;
83
-		$this->cloudFederationFactory = $cloudFederationFactory;
84
-		$this->eventDispatcher = $eventDispatcher;
85
-	}
86
-
87
-	/**
88
-	 * send server-to-server share to remote server
89
-	 *
90
-	 * @param string $token
91
-	 * @param string $shareWith
92
-	 * @param string $name
93
-	 * @param string $remoteId
94
-	 * @param string $owner
95
-	 * @param string $ownerFederatedId
96
-	 * @param string $sharedBy
97
-	 * @param string $sharedByFederatedId
98
-	 * @param int $shareType (can be a remote user or group share)
99
-	 * @return bool
100
-	 * @throws \OCP\HintException
101
-	 * @throws \OC\ServerNotAvailableException
102
-	 */
103
-	public function sendRemoteShare($token, $shareWith, $name, $remoteId, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType) {
104
-		[$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
105
-
106
-		if ($user && $remote) {
107
-			$local = $this->addressHandler->generateRemoteURL();
108
-
109
-			$fields = [
110
-				'shareWith' => $user,
111
-				'token' => $token,
112
-				'name' => $name,
113
-				'remoteId' => $remoteId,
114
-				'owner' => $owner,
115
-				'ownerFederatedId' => $ownerFederatedId,
116
-				'sharedBy' => $sharedBy,
117
-				'sharedByFederatedId' => $sharedByFederatedId,
118
-				'remote' => $local,
119
-				'shareType' => $shareType
120
-			];
121
-
122
-			$result = $this->tryHttpPostToShareEndpoint($remote, '', $fields);
123
-			$status = json_decode($result['result'], true);
124
-
125
-			$ocsStatus = isset($status['ocs']);
126
-			$ocsSuccess = $ocsStatus && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200);
127
-
128
-			if ($result['success'] && (!$ocsStatus || $ocsSuccess)) {
129
-				$event = new FederatedShareAddedEvent($remote);
130
-				$this->eventDispatcher->dispatchTyped($event);
131
-				return true;
132
-			} else {
133
-				$this->logger->info(
134
-					"failed sharing $name with $shareWith",
135
-					['app' => 'federatedfilesharing']
136
-				);
137
-			}
138
-		} else {
139
-			$this->logger->info(
140
-				"could not share $name, invalid contact $shareWith",
141
-				['app' => 'federatedfilesharing']
142
-			);
143
-		}
144
-
145
-		return false;
146
-	}
147
-
148
-	/**
149
-	 * ask owner to re-share the file with the given user
150
-	 *
151
-	 * @param string $token
152
-	 * @param string $id remote Id
153
-	 * @param string $shareId internal share Id
154
-	 * @param string $remote remote address of the owner
155
-	 * @param string $shareWith
156
-	 * @param int $permission
157
-	 * @param string $filename
158
-	 * @return array|false
159
-	 * @throws \OCP\HintException
160
-	 * @throws \OC\ServerNotAvailableException
161
-	 */
162
-	public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename) {
163
-		$fields = [
164
-			'shareWith' => $shareWith,
165
-			'token' => $token,
166
-			'permission' => $permission,
167
-			'remoteId' => $shareId,
168
-		];
169
-
170
-		$ocmFields = $fields;
171
-		$ocmFields['remoteId'] = (string)$id;
172
-		$ocmFields['localId'] = $shareId;
173
-		$ocmFields['name'] = $filename;
174
-
175
-		$ocmResult = $this->tryOCMEndPoint($remote, $ocmFields, 'reshare');
176
-		if (is_array($ocmResult) && isset($ocmResult['token']) && isset($ocmResult['providerId'])) {
177
-			return [$ocmResult['token'], $ocmResult['providerId']];
178
-		}
179
-
180
-		$result = $this->tryLegacyEndPoint(rtrim($remote, '/'), '/' . $id . '/reshare', $fields);
181
-		$status = json_decode($result['result'], true);
182
-
183
-		$httpRequestSuccessful = $result['success'];
184
-		$ocsCallSuccessful = $status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200;
185
-		$validToken = isset($status['ocs']['data']['token']) && is_string($status['ocs']['data']['token']);
186
-		$validRemoteId = isset($status['ocs']['data']['remoteId']);
187
-
188
-		if ($httpRequestSuccessful && $ocsCallSuccessful && $validToken && $validRemoteId) {
189
-			return [
190
-				$status['ocs']['data']['token'],
191
-				$status['ocs']['data']['remoteId']
192
-			];
193
-		} elseif (!$validToken) {
194
-			$this->logger->info(
195
-				"invalid or missing token requesting re-share for $filename to $remote",
196
-				['app' => 'federatedfilesharing']
197
-			);
198
-		} elseif (!$validRemoteId) {
199
-			$this->logger->info(
200
-				"missing remote id requesting re-share for $filename to $remote",
201
-				['app' => 'federatedfilesharing']
202
-			);
203
-		} else {
204
-			$this->logger->info(
205
-				"failed requesting re-share for $filename to $remote",
206
-				['app' => 'federatedfilesharing']
207
-			);
208
-		}
209
-
210
-		return false;
211
-	}
212
-
213
-	/**
214
-	 * send server-to-server unshare to remote server
215
-	 *
216
-	 * @param string $remote url
217
-	 * @param string $id share id
218
-	 * @param string $token
219
-	 * @return bool
220
-	 */
221
-	public function sendRemoteUnShare($remote, $id, $token) {
222
-		$this->sendUpdateToRemote($remote, $id, $token, 'unshare');
223
-	}
224
-
225
-	/**
226
-	 * send server-to-server unshare to remote server
227
-	 *
228
-	 * @param string $remote url
229
-	 * @param string $id share id
230
-	 * @param string $token
231
-	 * @return bool
232
-	 */
233
-	public function sendRevokeShare($remote, $id, $token) {
234
-		$this->sendUpdateToRemote($remote, $id, $token, 'reshare_undo');
235
-	}
236
-
237
-	/**
238
-	 * send notification to remote server if the permissions was changed
239
-	 *
240
-	 * @param string $remote
241
-	 * @param string $remoteId
242
-	 * @param string $token
243
-	 * @param int $permissions
244
-	 * @return bool
245
-	 */
246
-	public function sendPermissionChange($remote, $remoteId, $token, $permissions) {
247
-		$this->sendUpdateToRemote($remote, $remoteId, $token, 'permissions', ['permissions' => $permissions]);
248
-	}
249
-
250
-	/**
251
-	 * forward accept reShare to remote server
252
-	 *
253
-	 * @param string $remote
254
-	 * @param string $remoteId
255
-	 * @param string $token
256
-	 */
257
-	public function sendAcceptShare($remote, $remoteId, $token) {
258
-		$this->sendUpdateToRemote($remote, $remoteId, $token, 'accept');
259
-	}
260
-
261
-	/**
262
-	 * forward decline reShare to remote server
263
-	 *
264
-	 * @param string $remote
265
-	 * @param string $remoteId
266
-	 * @param string $token
267
-	 */
268
-	public function sendDeclineShare($remote, $remoteId, $token) {
269
-		$this->sendUpdateToRemote($remote, $remoteId, $token, 'decline');
270
-	}
271
-
272
-	/**
273
-	 * inform remote server whether server-to-server share was accepted/declined
274
-	 *
275
-	 * @param string $remote
276
-	 * @param string $token
277
-	 * @param string $remoteId Share id on the remote host
278
-	 * @param string $action possible actions: accept, decline, unshare, revoke, permissions
279
-	 * @param array $data
280
-	 * @param int $try
281
-	 * @return boolean
282
-	 */
283
-	public function sendUpdateToRemote($remote, $remoteId, $token, $action, $data = [], $try = 0) {
284
-		$fields = [
285
-			'token' => $token,
286
-			'remoteId' => $remoteId
287
-		];
288
-		foreach ($data as $key => $value) {
289
-			$fields[$key] = $value;
290
-		}
291
-
292
-		$result = $this->tryHttpPostToShareEndpoint(rtrim($remote, '/'), '/' . $remoteId . '/' . $action, $fields, $action);
293
-		$status = json_decode($result['result'], true);
294
-
295
-		if ($result['success'] &&
296
-			($status['ocs']['meta']['statuscode'] === 100 ||
297
-				$status['ocs']['meta']['statuscode'] === 200
298
-			)
299
-		) {
300
-			return true;
301
-		} elseif ($try === 0) {
302
-			// only add new job on first try
303
-			$this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob',
304
-				[
305
-					'remote' => $remote,
306
-					'remoteId' => $remoteId,
307
-					'token' => $token,
308
-					'action' => $action,
309
-					'data' => json_encode($data),
310
-					'try' => $try,
311
-					'lastRun' => $this->getTimestamp()
312
-				]
313
-			);
314
-		}
315
-
316
-		return false;
317
-	}
318
-
319
-
320
-	/**
321
-	 * return current timestamp
322
-	 *
323
-	 * @return int
324
-	 */
325
-	protected function getTimestamp() {
326
-		return time();
327
-	}
328
-
329
-	/**
330
-	 * try http post with the given protocol, if no protocol is given we pick
331
-	 * the secure one (https)
332
-	 *
333
-	 * @param string $remoteDomain
334
-	 * @param string $urlSuffix
335
-	 * @param array $fields post parameters
336
-	 * @param string $action define the action (possible values: share, reshare, accept, decline, unshare, revoke, permissions)
337
-	 * @return array
338
-	 * @throws \Exception
339
-	 */
340
-	protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields, $action = "share") {
341
-		if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) {
342
-			$remoteDomain = 'https://' . $remoteDomain;
343
-		}
344
-
345
-		$result = [
346
-			'success' => false,
347
-			'result' => '',
348
-		];
349
-
350
-		// if possible we use the new OCM API
351
-		$ocmResult = $this->tryOCMEndPoint($remoteDomain, $fields, $action);
352
-		if (is_array($ocmResult)) {
353
-			$result['success'] = true;
354
-			$result['result'] = json_encode([
355
-				'ocs' => ['meta' => ['statuscode' => 200]]]);
356
-			return $result;
357
-		}
358
-
359
-		return $this->tryLegacyEndPoint($remoteDomain, $urlSuffix, $fields);
360
-	}
361
-
362
-	/**
363
-	 * try old federated sharing API if the OCM api doesn't work
364
-	 *
365
-	 * @param $remoteDomain
366
-	 * @param $urlSuffix
367
-	 * @param array $fields
368
-	 * @return mixed
369
-	 * @throws \Exception
370
-	 */
371
-	protected function tryLegacyEndPoint($remoteDomain, $urlSuffix, array $fields) {
372
-		$result = [
373
-			'success' => false,
374
-			'result' => '',
375
-		];
376
-
377
-		// Fall back to old API
378
-		$client = $this->httpClientService->newClient();
379
-		$federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING');
380
-		$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
381
-		try {
382
-			$response = $client->post($remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, [
383
-				'body' => $fields,
384
-				'timeout' => 10,
385
-				'connect_timeout' => 10,
386
-			]);
387
-			$result['result'] = $response->getBody();
388
-			$result['success'] = true;
389
-		} catch (\Exception $e) {
390
-			// if flat re-sharing is not supported by the remote server
391
-			// we re-throw the exception and fall back to the old behaviour.
392
-			// (flat re-shares has been introduced in Nextcloud 9.1)
393
-			if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) {
394
-				throw $e;
395
-			}
396
-		}
397
-
398
-		return $result;
399
-	}
400
-
401
-	/**
402
-	 * send action regarding federated sharing to the remote server using the OCM API
403
-	 *
404
-	 * @param $remoteDomain
405
-	 * @param $fields
406
-	 * @param $action
407
-	 *
408
-	 * @return array|false
409
-	 */
410
-	protected function tryOCMEndPoint($remoteDomain, $fields, $action) {
411
-		switch ($action) {
412
-			case 'share':
413
-				$share = $this->cloudFederationFactory->getCloudFederationShare(
414
-					$fields['shareWith'] . '@' . $remoteDomain,
415
-					$fields['name'],
416
-					'',
417
-					$fields['remoteId'],
418
-					$fields['ownerFederatedId'],
419
-					$fields['owner'],
420
-					$fields['sharedByFederatedId'],
421
-					$fields['sharedBy'],
422
-					$fields['token'],
423
-					$fields['shareType'],
424
-					'file'
425
-				);
426
-				return $this->federationProviderManager->sendShare($share);
427
-			case 'reshare':
428
-				// ask owner to reshare a file
429
-				$notification = $this->cloudFederationFactory->getCloudFederationNotification();
430
-				$notification->setMessage('REQUEST_RESHARE',
431
-					'file',
432
-					$fields['remoteId'],
433
-					[
434
-						'sharedSecret' => $fields['token'],
435
-						'shareWith' => $fields['shareWith'],
436
-						'senderId' => $fields['localId'],
437
-						'shareType' => $fields['shareType'],
438
-						'message' => 'Ask owner to reshare the file'
439
-					]
440
-				);
441
-				return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
442
-			case 'unshare':
443
-				//owner unshares the file from the recipient again
444
-				$notification = $this->cloudFederationFactory->getCloudFederationNotification();
445
-				$notification->setMessage('SHARE_UNSHARED',
446
-					'file',
447
-					$fields['remoteId'],
448
-					[
449
-						'sharedSecret' => $fields['token'],
450
-						'messgage' => 'file is no longer shared with you'
451
-					]
452
-				);
453
-				return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
454
-			case 'reshare_undo':
455
-				// if a reshare was unshared we send the information to the initiator/owner
456
-				$notification = $this->cloudFederationFactory->getCloudFederationNotification();
457
-				$notification->setMessage('RESHARE_UNDO',
458
-					'file',
459
-					$fields['remoteId'],
460
-					[
461
-						'sharedSecret' => $fields['token'],
462
-						'message' => 'reshare was revoked'
463
-					]
464
-				);
465
-				return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
466
-		}
467
-
468
-		return false;
469
-	}
41
+    public const RESPONSE_FORMAT = 'json'; // default response format for ocs calls
42
+
43
+    /** @var AddressHandler */
44
+    private $addressHandler;
45
+
46
+    /** @var IClientService */
47
+    private $httpClientService;
48
+
49
+    /** @var IDiscoveryService */
50
+    private $discoveryService;
51
+
52
+    /** @var IJobList  */
53
+    private $jobList;
54
+
55
+    /** @var ICloudFederationProviderManager */
56
+    private $federationProviderManager;
57
+
58
+    /** @var ICloudFederationFactory */
59
+    private $cloudFederationFactory;
60
+
61
+    /** @var IEventDispatcher */
62
+    private $eventDispatcher;
63
+
64
+    /** @var ILogger */
65
+    private $logger;
66
+
67
+    public function __construct(
68
+        AddressHandler $addressHandler,
69
+        IClientService $httpClientService,
70
+        IDiscoveryService $discoveryService,
71
+        ILogger $logger,
72
+        IJobList $jobList,
73
+        ICloudFederationProviderManager $federationProviderManager,
74
+        ICloudFederationFactory $cloudFederationFactory,
75
+        IEventDispatcher $eventDispatcher
76
+    ) {
77
+        $this->addressHandler = $addressHandler;
78
+        $this->httpClientService = $httpClientService;
79
+        $this->discoveryService = $discoveryService;
80
+        $this->jobList = $jobList;
81
+        $this->logger = $logger;
82
+        $this->federationProviderManager = $federationProviderManager;
83
+        $this->cloudFederationFactory = $cloudFederationFactory;
84
+        $this->eventDispatcher = $eventDispatcher;
85
+    }
86
+
87
+    /**
88
+     * send server-to-server share to remote server
89
+     *
90
+     * @param string $token
91
+     * @param string $shareWith
92
+     * @param string $name
93
+     * @param string $remoteId
94
+     * @param string $owner
95
+     * @param string $ownerFederatedId
96
+     * @param string $sharedBy
97
+     * @param string $sharedByFederatedId
98
+     * @param int $shareType (can be a remote user or group share)
99
+     * @return bool
100
+     * @throws \OCP\HintException
101
+     * @throws \OC\ServerNotAvailableException
102
+     */
103
+    public function sendRemoteShare($token, $shareWith, $name, $remoteId, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType) {
104
+        [$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
105
+
106
+        if ($user && $remote) {
107
+            $local = $this->addressHandler->generateRemoteURL();
108
+
109
+            $fields = [
110
+                'shareWith' => $user,
111
+                'token' => $token,
112
+                'name' => $name,
113
+                'remoteId' => $remoteId,
114
+                'owner' => $owner,
115
+                'ownerFederatedId' => $ownerFederatedId,
116
+                'sharedBy' => $sharedBy,
117
+                'sharedByFederatedId' => $sharedByFederatedId,
118
+                'remote' => $local,
119
+                'shareType' => $shareType
120
+            ];
121
+
122
+            $result = $this->tryHttpPostToShareEndpoint($remote, '', $fields);
123
+            $status = json_decode($result['result'], true);
124
+
125
+            $ocsStatus = isset($status['ocs']);
126
+            $ocsSuccess = $ocsStatus && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200);
127
+
128
+            if ($result['success'] && (!$ocsStatus || $ocsSuccess)) {
129
+                $event = new FederatedShareAddedEvent($remote);
130
+                $this->eventDispatcher->dispatchTyped($event);
131
+                return true;
132
+            } else {
133
+                $this->logger->info(
134
+                    "failed sharing $name with $shareWith",
135
+                    ['app' => 'federatedfilesharing']
136
+                );
137
+            }
138
+        } else {
139
+            $this->logger->info(
140
+                "could not share $name, invalid contact $shareWith",
141
+                ['app' => 'federatedfilesharing']
142
+            );
143
+        }
144
+
145
+        return false;
146
+    }
147
+
148
+    /**
149
+     * ask owner to re-share the file with the given user
150
+     *
151
+     * @param string $token
152
+     * @param string $id remote Id
153
+     * @param string $shareId internal share Id
154
+     * @param string $remote remote address of the owner
155
+     * @param string $shareWith
156
+     * @param int $permission
157
+     * @param string $filename
158
+     * @return array|false
159
+     * @throws \OCP\HintException
160
+     * @throws \OC\ServerNotAvailableException
161
+     */
162
+    public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename) {
163
+        $fields = [
164
+            'shareWith' => $shareWith,
165
+            'token' => $token,
166
+            'permission' => $permission,
167
+            'remoteId' => $shareId,
168
+        ];
169
+
170
+        $ocmFields = $fields;
171
+        $ocmFields['remoteId'] = (string)$id;
172
+        $ocmFields['localId'] = $shareId;
173
+        $ocmFields['name'] = $filename;
174
+
175
+        $ocmResult = $this->tryOCMEndPoint($remote, $ocmFields, 'reshare');
176
+        if (is_array($ocmResult) && isset($ocmResult['token']) && isset($ocmResult['providerId'])) {
177
+            return [$ocmResult['token'], $ocmResult['providerId']];
178
+        }
179
+
180
+        $result = $this->tryLegacyEndPoint(rtrim($remote, '/'), '/' . $id . '/reshare', $fields);
181
+        $status = json_decode($result['result'], true);
182
+
183
+        $httpRequestSuccessful = $result['success'];
184
+        $ocsCallSuccessful = $status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200;
185
+        $validToken = isset($status['ocs']['data']['token']) && is_string($status['ocs']['data']['token']);
186
+        $validRemoteId = isset($status['ocs']['data']['remoteId']);
187
+
188
+        if ($httpRequestSuccessful && $ocsCallSuccessful && $validToken && $validRemoteId) {
189
+            return [
190
+                $status['ocs']['data']['token'],
191
+                $status['ocs']['data']['remoteId']
192
+            ];
193
+        } elseif (!$validToken) {
194
+            $this->logger->info(
195
+                "invalid or missing token requesting re-share for $filename to $remote",
196
+                ['app' => 'federatedfilesharing']
197
+            );
198
+        } elseif (!$validRemoteId) {
199
+            $this->logger->info(
200
+                "missing remote id requesting re-share for $filename to $remote",
201
+                ['app' => 'federatedfilesharing']
202
+            );
203
+        } else {
204
+            $this->logger->info(
205
+                "failed requesting re-share for $filename to $remote",
206
+                ['app' => 'federatedfilesharing']
207
+            );
208
+        }
209
+
210
+        return false;
211
+    }
212
+
213
+    /**
214
+     * send server-to-server unshare to remote server
215
+     *
216
+     * @param string $remote url
217
+     * @param string $id share id
218
+     * @param string $token
219
+     * @return bool
220
+     */
221
+    public function sendRemoteUnShare($remote, $id, $token) {
222
+        $this->sendUpdateToRemote($remote, $id, $token, 'unshare');
223
+    }
224
+
225
+    /**
226
+     * send server-to-server unshare to remote server
227
+     *
228
+     * @param string $remote url
229
+     * @param string $id share id
230
+     * @param string $token
231
+     * @return bool
232
+     */
233
+    public function sendRevokeShare($remote, $id, $token) {
234
+        $this->sendUpdateToRemote($remote, $id, $token, 'reshare_undo');
235
+    }
236
+
237
+    /**
238
+     * send notification to remote server if the permissions was changed
239
+     *
240
+     * @param string $remote
241
+     * @param string $remoteId
242
+     * @param string $token
243
+     * @param int $permissions
244
+     * @return bool
245
+     */
246
+    public function sendPermissionChange($remote, $remoteId, $token, $permissions) {
247
+        $this->sendUpdateToRemote($remote, $remoteId, $token, 'permissions', ['permissions' => $permissions]);
248
+    }
249
+
250
+    /**
251
+     * forward accept reShare to remote server
252
+     *
253
+     * @param string $remote
254
+     * @param string $remoteId
255
+     * @param string $token
256
+     */
257
+    public function sendAcceptShare($remote, $remoteId, $token) {
258
+        $this->sendUpdateToRemote($remote, $remoteId, $token, 'accept');
259
+    }
260
+
261
+    /**
262
+     * forward decline reShare to remote server
263
+     *
264
+     * @param string $remote
265
+     * @param string $remoteId
266
+     * @param string $token
267
+     */
268
+    public function sendDeclineShare($remote, $remoteId, $token) {
269
+        $this->sendUpdateToRemote($remote, $remoteId, $token, 'decline');
270
+    }
271
+
272
+    /**
273
+     * inform remote server whether server-to-server share was accepted/declined
274
+     *
275
+     * @param string $remote
276
+     * @param string $token
277
+     * @param string $remoteId Share id on the remote host
278
+     * @param string $action possible actions: accept, decline, unshare, revoke, permissions
279
+     * @param array $data
280
+     * @param int $try
281
+     * @return boolean
282
+     */
283
+    public function sendUpdateToRemote($remote, $remoteId, $token, $action, $data = [], $try = 0) {
284
+        $fields = [
285
+            'token' => $token,
286
+            'remoteId' => $remoteId
287
+        ];
288
+        foreach ($data as $key => $value) {
289
+            $fields[$key] = $value;
290
+        }
291
+
292
+        $result = $this->tryHttpPostToShareEndpoint(rtrim($remote, '/'), '/' . $remoteId . '/' . $action, $fields, $action);
293
+        $status = json_decode($result['result'], true);
294
+
295
+        if ($result['success'] &&
296
+            ($status['ocs']['meta']['statuscode'] === 100 ||
297
+                $status['ocs']['meta']['statuscode'] === 200
298
+            )
299
+        ) {
300
+            return true;
301
+        } elseif ($try === 0) {
302
+            // only add new job on first try
303
+            $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob',
304
+                [
305
+                    'remote' => $remote,
306
+                    'remoteId' => $remoteId,
307
+                    'token' => $token,
308
+                    'action' => $action,
309
+                    'data' => json_encode($data),
310
+                    'try' => $try,
311
+                    'lastRun' => $this->getTimestamp()
312
+                ]
313
+            );
314
+        }
315
+
316
+        return false;
317
+    }
318
+
319
+
320
+    /**
321
+     * return current timestamp
322
+     *
323
+     * @return int
324
+     */
325
+    protected function getTimestamp() {
326
+        return time();
327
+    }
328
+
329
+    /**
330
+     * try http post with the given protocol, if no protocol is given we pick
331
+     * the secure one (https)
332
+     *
333
+     * @param string $remoteDomain
334
+     * @param string $urlSuffix
335
+     * @param array $fields post parameters
336
+     * @param string $action define the action (possible values: share, reshare, accept, decline, unshare, revoke, permissions)
337
+     * @return array
338
+     * @throws \Exception
339
+     */
340
+    protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields, $action = "share") {
341
+        if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) {
342
+            $remoteDomain = 'https://' . $remoteDomain;
343
+        }
344
+
345
+        $result = [
346
+            'success' => false,
347
+            'result' => '',
348
+        ];
349
+
350
+        // if possible we use the new OCM API
351
+        $ocmResult = $this->tryOCMEndPoint($remoteDomain, $fields, $action);
352
+        if (is_array($ocmResult)) {
353
+            $result['success'] = true;
354
+            $result['result'] = json_encode([
355
+                'ocs' => ['meta' => ['statuscode' => 200]]]);
356
+            return $result;
357
+        }
358
+
359
+        return $this->tryLegacyEndPoint($remoteDomain, $urlSuffix, $fields);
360
+    }
361
+
362
+    /**
363
+     * try old federated sharing API if the OCM api doesn't work
364
+     *
365
+     * @param $remoteDomain
366
+     * @param $urlSuffix
367
+     * @param array $fields
368
+     * @return mixed
369
+     * @throws \Exception
370
+     */
371
+    protected function tryLegacyEndPoint($remoteDomain, $urlSuffix, array $fields) {
372
+        $result = [
373
+            'success' => false,
374
+            'result' => '',
375
+        ];
376
+
377
+        // Fall back to old API
378
+        $client = $this->httpClientService->newClient();
379
+        $federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING');
380
+        $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
381
+        try {
382
+            $response = $client->post($remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, [
383
+                'body' => $fields,
384
+                'timeout' => 10,
385
+                'connect_timeout' => 10,
386
+            ]);
387
+            $result['result'] = $response->getBody();
388
+            $result['success'] = true;
389
+        } catch (\Exception $e) {
390
+            // if flat re-sharing is not supported by the remote server
391
+            // we re-throw the exception and fall back to the old behaviour.
392
+            // (flat re-shares has been introduced in Nextcloud 9.1)
393
+            if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) {
394
+                throw $e;
395
+            }
396
+        }
397
+
398
+        return $result;
399
+    }
400
+
401
+    /**
402
+     * send action regarding federated sharing to the remote server using the OCM API
403
+     *
404
+     * @param $remoteDomain
405
+     * @param $fields
406
+     * @param $action
407
+     *
408
+     * @return array|false
409
+     */
410
+    protected function tryOCMEndPoint($remoteDomain, $fields, $action) {
411
+        switch ($action) {
412
+            case 'share':
413
+                $share = $this->cloudFederationFactory->getCloudFederationShare(
414
+                    $fields['shareWith'] . '@' . $remoteDomain,
415
+                    $fields['name'],
416
+                    '',
417
+                    $fields['remoteId'],
418
+                    $fields['ownerFederatedId'],
419
+                    $fields['owner'],
420
+                    $fields['sharedByFederatedId'],
421
+                    $fields['sharedBy'],
422
+                    $fields['token'],
423
+                    $fields['shareType'],
424
+                    'file'
425
+                );
426
+                return $this->federationProviderManager->sendShare($share);
427
+            case 'reshare':
428
+                // ask owner to reshare a file
429
+                $notification = $this->cloudFederationFactory->getCloudFederationNotification();
430
+                $notification->setMessage('REQUEST_RESHARE',
431
+                    'file',
432
+                    $fields['remoteId'],
433
+                    [
434
+                        'sharedSecret' => $fields['token'],
435
+                        'shareWith' => $fields['shareWith'],
436
+                        'senderId' => $fields['localId'],
437
+                        'shareType' => $fields['shareType'],
438
+                        'message' => 'Ask owner to reshare the file'
439
+                    ]
440
+                );
441
+                return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
442
+            case 'unshare':
443
+                //owner unshares the file from the recipient again
444
+                $notification = $this->cloudFederationFactory->getCloudFederationNotification();
445
+                $notification->setMessage('SHARE_UNSHARED',
446
+                    'file',
447
+                    $fields['remoteId'],
448
+                    [
449
+                        'sharedSecret' => $fields['token'],
450
+                        'messgage' => 'file is no longer shared with you'
451
+                    ]
452
+                );
453
+                return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
454
+            case 'reshare_undo':
455
+                // if a reshare was unshared we send the information to the initiator/owner
456
+                $notification = $this->cloudFederationFactory->getCloudFederationNotification();
457
+                $notification->setMessage('RESHARE_UNDO',
458
+                    'file',
459
+                    $fields['remoteId'],
460
+                    [
461
+                        'sharedSecret' => $fields['token'],
462
+                        'message' => 'reshare was revoked'
463
+                    ]
464
+                );
465
+                return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
466
+        }
467
+
468
+        return false;
469
+    }
470 470
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/FederatedShareProvider.php 1 patch
Indentation   +1076 added lines, -1076 removed lines patch added patch discarded remove patch
@@ -63,1090 +63,1090 @@
 block discarded – undo
63 63
  * @package OCA\FederatedFileSharing
64 64
  */
65 65
 class FederatedShareProvider implements IShareProvider {
66
-	public const SHARE_TYPE_REMOTE = 6;
67
-
68
-	/** @var IDBConnection */
69
-	private $dbConnection;
70
-
71
-	/** @var AddressHandler */
72
-	private $addressHandler;
73
-
74
-	/** @var Notifications */
75
-	private $notifications;
76
-
77
-	/** @var TokenHandler */
78
-	private $tokenHandler;
79
-
80
-	/** @var IL10N */
81
-	private $l;
82
-
83
-	/** @var ILogger */
84
-	private $logger;
85
-
86
-	/** @var IRootFolder */
87
-	private $rootFolder;
88
-
89
-	/** @var IConfig */
90
-	private $config;
91
-
92
-	/** @var string */
93
-	private $externalShareTable = 'share_external';
94
-
95
-	/** @var IUserManager */
96
-	private $userManager;
97
-
98
-	/** @var ICloudIdManager */
99
-	private $cloudIdManager;
100
-
101
-	/** @var \OCP\GlobalScale\IConfig */
102
-	private $gsConfig;
103
-
104
-	/** @var ICloudFederationProviderManager */
105
-	private $cloudFederationProviderManager;
106
-
107
-	/** @var array list of supported share types */
108
-	private $supportedShareType = [IShare::TYPE_REMOTE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE];
109
-
110
-	/**
111
-	 * DefaultShareProvider constructor.
112
-	 *
113
-	 * @param IDBConnection $connection
114
-	 * @param AddressHandler $addressHandler
115
-	 * @param Notifications $notifications
116
-	 * @param TokenHandler $tokenHandler
117
-	 * @param IL10N $l10n
118
-	 * @param ILogger $logger
119
-	 * @param IRootFolder $rootFolder
120
-	 * @param IConfig $config
121
-	 * @param IUserManager $userManager
122
-	 * @param ICloudIdManager $cloudIdManager
123
-	 * @param \OCP\GlobalScale\IConfig $globalScaleConfig
124
-	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
125
-	 */
126
-	public function __construct(
127
-			IDBConnection $connection,
128
-			AddressHandler $addressHandler,
129
-			Notifications $notifications,
130
-			TokenHandler $tokenHandler,
131
-			IL10N $l10n,
132
-			ILogger $logger,
133
-			IRootFolder $rootFolder,
134
-			IConfig $config,
135
-			IUserManager $userManager,
136
-			ICloudIdManager $cloudIdManager,
137
-			\OCP\GlobalScale\IConfig $globalScaleConfig,
138
-			ICloudFederationProviderManager $cloudFederationProviderManager
139
-	) {
140
-		$this->dbConnection = $connection;
141
-		$this->addressHandler = $addressHandler;
142
-		$this->notifications = $notifications;
143
-		$this->tokenHandler = $tokenHandler;
144
-		$this->l = $l10n;
145
-		$this->logger = $logger;
146
-		$this->rootFolder = $rootFolder;
147
-		$this->config = $config;
148
-		$this->userManager = $userManager;
149
-		$this->cloudIdManager = $cloudIdManager;
150
-		$this->gsConfig = $globalScaleConfig;
151
-		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
152
-	}
153
-
154
-	/**
155
-	 * Return the identifier of this provider.
156
-	 *
157
-	 * @return string Containing only [a-zA-Z0-9]
158
-	 */
159
-	public function identifier() {
160
-		return 'ocFederatedSharing';
161
-	}
162
-
163
-	/**
164
-	 * Share a path
165
-	 *
166
-	 * @param IShare $share
167
-	 * @return IShare The share object
168
-	 * @throws ShareNotFound
169
-	 * @throws \Exception
170
-	 */
171
-	public function create(IShare $share) {
172
-		$shareWith = $share->getSharedWith();
173
-		$itemSource = $share->getNodeId();
174
-		$itemType = $share->getNodeType();
175
-		$permissions = $share->getPermissions();
176
-		$sharedBy = $share->getSharedBy();
177
-		$shareType = $share->getShareType();
178
-		$expirationDate = $share->getExpirationDate();
179
-
180
-		if ($shareType === IShare::TYPE_REMOTE_GROUP &&
181
-			!$this->isOutgoingServer2serverGroupShareEnabled()
182
-		) {
183
-			$message = 'It is not allowed to send federated group shares from this server.';
184
-			$message_t = $this->l->t('It is not allowed to send federated group shares from this server.');
185
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
186
-			throw new \Exception($message_t);
187
-		}
188
-
189
-		/*
66
+    public const SHARE_TYPE_REMOTE = 6;
67
+
68
+    /** @var IDBConnection */
69
+    private $dbConnection;
70
+
71
+    /** @var AddressHandler */
72
+    private $addressHandler;
73
+
74
+    /** @var Notifications */
75
+    private $notifications;
76
+
77
+    /** @var TokenHandler */
78
+    private $tokenHandler;
79
+
80
+    /** @var IL10N */
81
+    private $l;
82
+
83
+    /** @var ILogger */
84
+    private $logger;
85
+
86
+    /** @var IRootFolder */
87
+    private $rootFolder;
88
+
89
+    /** @var IConfig */
90
+    private $config;
91
+
92
+    /** @var string */
93
+    private $externalShareTable = 'share_external';
94
+
95
+    /** @var IUserManager */
96
+    private $userManager;
97
+
98
+    /** @var ICloudIdManager */
99
+    private $cloudIdManager;
100
+
101
+    /** @var \OCP\GlobalScale\IConfig */
102
+    private $gsConfig;
103
+
104
+    /** @var ICloudFederationProviderManager */
105
+    private $cloudFederationProviderManager;
106
+
107
+    /** @var array list of supported share types */
108
+    private $supportedShareType = [IShare::TYPE_REMOTE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE];
109
+
110
+    /**
111
+     * DefaultShareProvider constructor.
112
+     *
113
+     * @param IDBConnection $connection
114
+     * @param AddressHandler $addressHandler
115
+     * @param Notifications $notifications
116
+     * @param TokenHandler $tokenHandler
117
+     * @param IL10N $l10n
118
+     * @param ILogger $logger
119
+     * @param IRootFolder $rootFolder
120
+     * @param IConfig $config
121
+     * @param IUserManager $userManager
122
+     * @param ICloudIdManager $cloudIdManager
123
+     * @param \OCP\GlobalScale\IConfig $globalScaleConfig
124
+     * @param ICloudFederationProviderManager $cloudFederationProviderManager
125
+     */
126
+    public function __construct(
127
+            IDBConnection $connection,
128
+            AddressHandler $addressHandler,
129
+            Notifications $notifications,
130
+            TokenHandler $tokenHandler,
131
+            IL10N $l10n,
132
+            ILogger $logger,
133
+            IRootFolder $rootFolder,
134
+            IConfig $config,
135
+            IUserManager $userManager,
136
+            ICloudIdManager $cloudIdManager,
137
+            \OCP\GlobalScale\IConfig $globalScaleConfig,
138
+            ICloudFederationProviderManager $cloudFederationProviderManager
139
+    ) {
140
+        $this->dbConnection = $connection;
141
+        $this->addressHandler = $addressHandler;
142
+        $this->notifications = $notifications;
143
+        $this->tokenHandler = $tokenHandler;
144
+        $this->l = $l10n;
145
+        $this->logger = $logger;
146
+        $this->rootFolder = $rootFolder;
147
+        $this->config = $config;
148
+        $this->userManager = $userManager;
149
+        $this->cloudIdManager = $cloudIdManager;
150
+        $this->gsConfig = $globalScaleConfig;
151
+        $this->cloudFederationProviderManager = $cloudFederationProviderManager;
152
+    }
153
+
154
+    /**
155
+     * Return the identifier of this provider.
156
+     *
157
+     * @return string Containing only [a-zA-Z0-9]
158
+     */
159
+    public function identifier() {
160
+        return 'ocFederatedSharing';
161
+    }
162
+
163
+    /**
164
+     * Share a path
165
+     *
166
+     * @param IShare $share
167
+     * @return IShare The share object
168
+     * @throws ShareNotFound
169
+     * @throws \Exception
170
+     */
171
+    public function create(IShare $share) {
172
+        $shareWith = $share->getSharedWith();
173
+        $itemSource = $share->getNodeId();
174
+        $itemType = $share->getNodeType();
175
+        $permissions = $share->getPermissions();
176
+        $sharedBy = $share->getSharedBy();
177
+        $shareType = $share->getShareType();
178
+        $expirationDate = $share->getExpirationDate();
179
+
180
+        if ($shareType === IShare::TYPE_REMOTE_GROUP &&
181
+            !$this->isOutgoingServer2serverGroupShareEnabled()
182
+        ) {
183
+            $message = 'It is not allowed to send federated group shares from this server.';
184
+            $message_t = $this->l->t('It is not allowed to send federated group shares from this server.');
185
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
186
+            throw new \Exception($message_t);
187
+        }
188
+
189
+        /*
190 190
 		 * Check if file is not already shared with the remote user
191 191
 		 */
192
-		$alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE, $share->getNode(), 1, 0);
193
-		$alreadySharedGroup = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE_GROUP, $share->getNode(), 1, 0);
194
-		if (!empty($alreadyShared) || !empty($alreadySharedGroup)) {
195
-			$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
196
-			$message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with user %2$s', [$share->getNode()->getName(), $shareWith]);
197
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
198
-			throw new \Exception($message_t);
199
-		}
200
-
201
-
202
-		// don't allow federated shares if source and target server are the same
203
-		$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
204
-		$currentServer = $this->addressHandler->generateRemoteURL();
205
-		$currentUser = $sharedBy;
206
-		if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
207
-			$message = 'Not allowed to create a federated share with the same user.';
208
-			$message_t = $this->l->t('Not allowed to create a federated share with the same user');
209
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
210
-			throw new \Exception($message_t);
211
-		}
212
-
213
-		// Federated shares always have read permissions
214
-		if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
215
-			$message = 'Federated shares require read permissions';
216
-			$message_t = $this->l->t('Federated shares require read permissions');
217
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
218
-			throw new \Exception($message_t);
219
-		}
220
-
221
-		$share->setSharedWith($cloudId->getId());
222
-
223
-		try {
224
-			$remoteShare = $this->getShareFromExternalShareTable($share);
225
-		} catch (ShareNotFound $e) {
226
-			$remoteShare = null;
227
-		}
228
-
229
-		if ($remoteShare) {
230
-			try {
231
-				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
232
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType, $expirationDate);
233
-				$share->setId($shareId);
234
-				[$token, $remoteId] = $this->askOwnerToReShare($shareWith, $share, $shareId);
235
-				// remote share was create successfully if we get a valid token as return
236
-				$send = is_string($token) && $token !== '';
237
-			} catch (\Exception $e) {
238
-				// fall back to old re-share behavior if the remote server
239
-				// doesn't support flat re-shares (was introduced with Nextcloud 9.1)
240
-				$this->removeShareFromTable($share);
241
-				$shareId = $this->createFederatedShare($share);
242
-			}
243
-			if ($send) {
244
-				$this->updateSuccessfulReshare($shareId, $token);
245
-				$this->storeRemoteId($shareId, $remoteId);
246
-			} else {
247
-				$this->removeShareFromTable($share);
248
-				$message_t = $this->l->t('File is already shared with %s', [$shareWith]);
249
-				throw new \Exception($message_t);
250
-			}
251
-		} else {
252
-			$shareId = $this->createFederatedShare($share);
253
-		}
254
-
255
-		$data = $this->getRawShare($shareId);
256
-		return $this->createShareObject($data);
257
-	}
258
-
259
-	/**
260
-	 * create federated share and inform the recipient
261
-	 *
262
-	 * @param IShare $share
263
-	 * @return int
264
-	 * @throws ShareNotFound
265
-	 * @throws \Exception
266
-	 */
267
-	protected function createFederatedShare(IShare $share) {
268
-		$token = $this->tokenHandler->generateToken();
269
-		$shareId = $this->addShareToDB(
270
-			$share->getNodeId(),
271
-			$share->getNodeType(),
272
-			$share->getSharedWith(),
273
-			$share->getSharedBy(),
274
-			$share->getShareOwner(),
275
-			$share->getPermissions(),
276
-			$token,
277
-			$share->getShareType(),
278
-			$share->getExpirationDate()
279
-		);
280
-
281
-		$failure = false;
282
-
283
-		try {
284
-			$sharedByFederatedId = $share->getSharedBy();
285
-			if ($this->userManager->userExists($sharedByFederatedId)) {
286
-				$cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
287
-				$sharedByFederatedId = $cloudId->getId();
288
-			}
289
-			$ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
290
-			$send = $this->notifications->sendRemoteShare(
291
-				$token,
292
-				$share->getSharedWith(),
293
-				$share->getNode()->getName(),
294
-				$shareId,
295
-				$share->getShareOwner(),
296
-				$ownerCloudId->getId(),
297
-				$share->getSharedBy(),
298
-				$sharedByFederatedId,
299
-				$share->getShareType()
300
-			);
301
-
302
-			if ($send === false) {
303
-				$failure = true;
304
-			}
305
-		} catch (\Exception $e) {
306
-			$this->logger->logException($e, [
307
-				'message' => 'Failed to notify remote server of federated share, removing share.',
308
-				'level' => ILogger::ERROR,
309
-				'app' => 'federatedfilesharing',
310
-			]);
311
-			$failure = true;
312
-		}
313
-
314
-		if ($failure) {
315
-			$this->removeShareFromTableById($shareId);
316
-			$message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.',
317
-				[$share->getNode()->getName(), $share->getSharedWith()]);
318
-			throw new \Exception($message_t);
319
-		}
320
-
321
-		return $shareId;
322
-	}
323
-
324
-	/**
325
-	 * @param string $shareWith
326
-	 * @param IShare $share
327
-	 * @param string $shareId internal share Id
328
-	 * @return array
329
-	 * @throws \Exception
330
-	 */
331
-	protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
332
-		$remoteShare = $this->getShareFromExternalShareTable($share);
333
-		$token = $remoteShare['share_token'];
334
-		$remoteId = $remoteShare['remote_id'];
335
-		$remote = $remoteShare['remote'];
336
-
337
-		[$token, $remoteId] = $this->notifications->requestReShare(
338
-			$token,
339
-			$remoteId,
340
-			$shareId,
341
-			$remote,
342
-			$shareWith,
343
-			$share->getPermissions(),
344
-			$share->getNode()->getName()
345
-		);
346
-
347
-		return [$token, $remoteId];
348
-	}
349
-
350
-	/**
351
-	 * get federated share from the share_external table but exclude mounted link shares
352
-	 *
353
-	 * @param IShare $share
354
-	 * @return array
355
-	 * @throws ShareNotFound
356
-	 */
357
-	protected function getShareFromExternalShareTable(IShare $share) {
358
-		$query = $this->dbConnection->getQueryBuilder();
359
-		$query->select('*')->from($this->externalShareTable)
360
-			->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
361
-			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
362
-		$qResult = $query->execute();
363
-		$result = $qResult->fetchAll();
364
-		$qResult->closeCursor();
365
-
366
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
367
-			return $result[0];
368
-		}
369
-
370
-		throw new ShareNotFound('share not found in share_external table');
371
-	}
372
-
373
-	/**
374
-	 * add share to the database and return the ID
375
-	 *
376
-	 * @param int $itemSource
377
-	 * @param string $itemType
378
-	 * @param string $shareWith
379
-	 * @param string $sharedBy
380
-	 * @param string $uidOwner
381
-	 * @param int $permissions
382
-	 * @param string $token
383
-	 * @param int $shareType
384
-	 * @param \DateTime $expirationDate
385
-	 * @return int
386
-	 */
387
-	private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType, $expirationDate) {
388
-		$qb = $this->dbConnection->getQueryBuilder();
389
-		$qb->insert('share')
390
-			->setValue('share_type', $qb->createNamedParameter($shareType))
391
-			->setValue('item_type', $qb->createNamedParameter($itemType))
392
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
393
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
394
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
395
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
396
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
397
-			->setValue('permissions', $qb->createNamedParameter($permissions))
398
-			->setValue('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
399
-			->setValue('token', $qb->createNamedParameter($token))
400
-			->setValue('stime', $qb->createNamedParameter(time()));
401
-
402
-		/*
192
+        $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE, $share->getNode(), 1, 0);
193
+        $alreadySharedGroup = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE_GROUP, $share->getNode(), 1, 0);
194
+        if (!empty($alreadyShared) || !empty($alreadySharedGroup)) {
195
+            $message = 'Sharing %1$s failed, because this item is already shared with %2$s';
196
+            $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with user %2$s', [$share->getNode()->getName(), $shareWith]);
197
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
198
+            throw new \Exception($message_t);
199
+        }
200
+
201
+
202
+        // don't allow federated shares if source and target server are the same
203
+        $cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
204
+        $currentServer = $this->addressHandler->generateRemoteURL();
205
+        $currentUser = $sharedBy;
206
+        if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
207
+            $message = 'Not allowed to create a federated share with the same user.';
208
+            $message_t = $this->l->t('Not allowed to create a federated share with the same user');
209
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
210
+            throw new \Exception($message_t);
211
+        }
212
+
213
+        // Federated shares always have read permissions
214
+        if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
215
+            $message = 'Federated shares require read permissions';
216
+            $message_t = $this->l->t('Federated shares require read permissions');
217
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
218
+            throw new \Exception($message_t);
219
+        }
220
+
221
+        $share->setSharedWith($cloudId->getId());
222
+
223
+        try {
224
+            $remoteShare = $this->getShareFromExternalShareTable($share);
225
+        } catch (ShareNotFound $e) {
226
+            $remoteShare = null;
227
+        }
228
+
229
+        if ($remoteShare) {
230
+            try {
231
+                $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
232
+                $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType, $expirationDate);
233
+                $share->setId($shareId);
234
+                [$token, $remoteId] = $this->askOwnerToReShare($shareWith, $share, $shareId);
235
+                // remote share was create successfully if we get a valid token as return
236
+                $send = is_string($token) && $token !== '';
237
+            } catch (\Exception $e) {
238
+                // fall back to old re-share behavior if the remote server
239
+                // doesn't support flat re-shares (was introduced with Nextcloud 9.1)
240
+                $this->removeShareFromTable($share);
241
+                $shareId = $this->createFederatedShare($share);
242
+            }
243
+            if ($send) {
244
+                $this->updateSuccessfulReshare($shareId, $token);
245
+                $this->storeRemoteId($shareId, $remoteId);
246
+            } else {
247
+                $this->removeShareFromTable($share);
248
+                $message_t = $this->l->t('File is already shared with %s', [$shareWith]);
249
+                throw new \Exception($message_t);
250
+            }
251
+        } else {
252
+            $shareId = $this->createFederatedShare($share);
253
+        }
254
+
255
+        $data = $this->getRawShare($shareId);
256
+        return $this->createShareObject($data);
257
+    }
258
+
259
+    /**
260
+     * create federated share and inform the recipient
261
+     *
262
+     * @param IShare $share
263
+     * @return int
264
+     * @throws ShareNotFound
265
+     * @throws \Exception
266
+     */
267
+    protected function createFederatedShare(IShare $share) {
268
+        $token = $this->tokenHandler->generateToken();
269
+        $shareId = $this->addShareToDB(
270
+            $share->getNodeId(),
271
+            $share->getNodeType(),
272
+            $share->getSharedWith(),
273
+            $share->getSharedBy(),
274
+            $share->getShareOwner(),
275
+            $share->getPermissions(),
276
+            $token,
277
+            $share->getShareType(),
278
+            $share->getExpirationDate()
279
+        );
280
+
281
+        $failure = false;
282
+
283
+        try {
284
+            $sharedByFederatedId = $share->getSharedBy();
285
+            if ($this->userManager->userExists($sharedByFederatedId)) {
286
+                $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
287
+                $sharedByFederatedId = $cloudId->getId();
288
+            }
289
+            $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
290
+            $send = $this->notifications->sendRemoteShare(
291
+                $token,
292
+                $share->getSharedWith(),
293
+                $share->getNode()->getName(),
294
+                $shareId,
295
+                $share->getShareOwner(),
296
+                $ownerCloudId->getId(),
297
+                $share->getSharedBy(),
298
+                $sharedByFederatedId,
299
+                $share->getShareType()
300
+            );
301
+
302
+            if ($send === false) {
303
+                $failure = true;
304
+            }
305
+        } catch (\Exception $e) {
306
+            $this->logger->logException($e, [
307
+                'message' => 'Failed to notify remote server of federated share, removing share.',
308
+                'level' => ILogger::ERROR,
309
+                'app' => 'federatedfilesharing',
310
+            ]);
311
+            $failure = true;
312
+        }
313
+
314
+        if ($failure) {
315
+            $this->removeShareFromTableById($shareId);
316
+            $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.',
317
+                [$share->getNode()->getName(), $share->getSharedWith()]);
318
+            throw new \Exception($message_t);
319
+        }
320
+
321
+        return $shareId;
322
+    }
323
+
324
+    /**
325
+     * @param string $shareWith
326
+     * @param IShare $share
327
+     * @param string $shareId internal share Id
328
+     * @return array
329
+     * @throws \Exception
330
+     */
331
+    protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
332
+        $remoteShare = $this->getShareFromExternalShareTable($share);
333
+        $token = $remoteShare['share_token'];
334
+        $remoteId = $remoteShare['remote_id'];
335
+        $remote = $remoteShare['remote'];
336
+
337
+        [$token, $remoteId] = $this->notifications->requestReShare(
338
+            $token,
339
+            $remoteId,
340
+            $shareId,
341
+            $remote,
342
+            $shareWith,
343
+            $share->getPermissions(),
344
+            $share->getNode()->getName()
345
+        );
346
+
347
+        return [$token, $remoteId];
348
+    }
349
+
350
+    /**
351
+     * get federated share from the share_external table but exclude mounted link shares
352
+     *
353
+     * @param IShare $share
354
+     * @return array
355
+     * @throws ShareNotFound
356
+     */
357
+    protected function getShareFromExternalShareTable(IShare $share) {
358
+        $query = $this->dbConnection->getQueryBuilder();
359
+        $query->select('*')->from($this->externalShareTable)
360
+            ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
361
+            ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
362
+        $qResult = $query->execute();
363
+        $result = $qResult->fetchAll();
364
+        $qResult->closeCursor();
365
+
366
+        if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
367
+            return $result[0];
368
+        }
369
+
370
+        throw new ShareNotFound('share not found in share_external table');
371
+    }
372
+
373
+    /**
374
+     * add share to the database and return the ID
375
+     *
376
+     * @param int $itemSource
377
+     * @param string $itemType
378
+     * @param string $shareWith
379
+     * @param string $sharedBy
380
+     * @param string $uidOwner
381
+     * @param int $permissions
382
+     * @param string $token
383
+     * @param int $shareType
384
+     * @param \DateTime $expirationDate
385
+     * @return int
386
+     */
387
+    private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType, $expirationDate) {
388
+        $qb = $this->dbConnection->getQueryBuilder();
389
+        $qb->insert('share')
390
+            ->setValue('share_type', $qb->createNamedParameter($shareType))
391
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
392
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
393
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
394
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
395
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
396
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
397
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
398
+            ->setValue('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
399
+            ->setValue('token', $qb->createNamedParameter($token))
400
+            ->setValue('stime', $qb->createNamedParameter(time()));
401
+
402
+        /*
403 403
 		 * Added to fix https://github.com/owncloud/core/issues/22215
404 404
 		 * Can be removed once we get rid of ajax/share.php
405 405
 		 */
406
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
407
-
408
-		$qb->execute();
409
-		return $qb->getLastInsertId();
410
-	}
411
-
412
-	/**
413
-	 * Update a share
414
-	 *
415
-	 * @param IShare $share
416
-	 * @return IShare The share object
417
-	 */
418
-	public function update(IShare $share) {
419
-		/*
406
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
407
+
408
+        $qb->execute();
409
+        return $qb->getLastInsertId();
410
+    }
411
+
412
+    /**
413
+     * Update a share
414
+     *
415
+     * @param IShare $share
416
+     * @return IShare The share object
417
+     */
418
+    public function update(IShare $share) {
419
+        /*
420 420
 		 * We allow updating the permissions of federated shares
421 421
 		 */
422
-		$qb = $this->dbConnection->getQueryBuilder();
423
-		$qb->update('share')
424
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
425
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
426
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
427
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
428
-				->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
429
-				->execute();
430
-
431
-		// send the updated permission to the owner/initiator, if they are not the same
432
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
433
-			$this->sendPermissionUpdate($share);
434
-		}
435
-
436
-		return $share;
437
-	}
438
-
439
-	/**
440
-	 * send the updated permission to the owner/initiator, if they are not the same
441
-	 *
442
-	 * @param IShare $share
443
-	 * @throws ShareNotFound
444
-	 * @throws \OCP\HintException
445
-	 */
446
-	protected function sendPermissionUpdate(IShare $share) {
447
-		$remoteId = $this->getRemoteId($share);
448
-		// if the local user is the owner we send the permission change to the initiator
449
-		if ($this->userManager->userExists($share->getShareOwner())) {
450
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
451
-		} else { // ... if not we send the permission change to the owner
452
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
453
-		}
454
-		$this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
455
-	}
456
-
457
-
458
-	/**
459
-	 * update successful reShare with the correct token
460
-	 *
461
-	 * @param int $shareId
462
-	 * @param string $token
463
-	 */
464
-	protected function updateSuccessfulReShare($shareId, $token) {
465
-		$query = $this->dbConnection->getQueryBuilder();
466
-		$query->update('share')
467
-			->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
468
-			->set('token', $query->createNamedParameter($token))
469
-			->execute();
470
-	}
471
-
472
-	/**
473
-	 * store remote ID in federated reShare table
474
-	 *
475
-	 * @param $shareId
476
-	 * @param $remoteId
477
-	 */
478
-	public function storeRemoteId(int $shareId, string $remoteId): void {
479
-		$query = $this->dbConnection->getQueryBuilder();
480
-		$query->insert('federated_reshares')
481
-			->values(
482
-				[
483
-					'share_id' => $query->createNamedParameter($shareId),
484
-					'remote_id' => $query->createNamedParameter($remoteId),
485
-				]
486
-			);
487
-		$query->execute();
488
-	}
489
-
490
-	/**
491
-	 * get share ID on remote server for federated re-shares
492
-	 *
493
-	 * @param IShare $share
494
-	 * @return string
495
-	 * @throws ShareNotFound
496
-	 */
497
-	public function getRemoteId(IShare $share): string {
498
-		$query = $this->dbConnection->getQueryBuilder();
499
-		$query->select('remote_id')->from('federated_reshares')
500
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
501
-		$result = $query->execute();
502
-		$data = $result->fetch();
503
-		$result->closeCursor();
504
-
505
-		if (!is_array($data) || !isset($data['remote_id'])) {
506
-			throw new ShareNotFound();
507
-		}
508
-
509
-		return (string)$data['remote_id'];
510
-	}
511
-
512
-	/**
513
-	 * @inheritdoc
514
-	 */
515
-	public function move(IShare $share, $recipient) {
516
-		/*
422
+        $qb = $this->dbConnection->getQueryBuilder();
423
+        $qb->update('share')
424
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
425
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
426
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
427
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
428
+                ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
429
+                ->execute();
430
+
431
+        // send the updated permission to the owner/initiator, if they are not the same
432
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
433
+            $this->sendPermissionUpdate($share);
434
+        }
435
+
436
+        return $share;
437
+    }
438
+
439
+    /**
440
+     * send the updated permission to the owner/initiator, if they are not the same
441
+     *
442
+     * @param IShare $share
443
+     * @throws ShareNotFound
444
+     * @throws \OCP\HintException
445
+     */
446
+    protected function sendPermissionUpdate(IShare $share) {
447
+        $remoteId = $this->getRemoteId($share);
448
+        // if the local user is the owner we send the permission change to the initiator
449
+        if ($this->userManager->userExists($share->getShareOwner())) {
450
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
451
+        } else { // ... if not we send the permission change to the owner
452
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
453
+        }
454
+        $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
455
+    }
456
+
457
+
458
+    /**
459
+     * update successful reShare with the correct token
460
+     *
461
+     * @param int $shareId
462
+     * @param string $token
463
+     */
464
+    protected function updateSuccessfulReShare($shareId, $token) {
465
+        $query = $this->dbConnection->getQueryBuilder();
466
+        $query->update('share')
467
+            ->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
468
+            ->set('token', $query->createNamedParameter($token))
469
+            ->execute();
470
+    }
471
+
472
+    /**
473
+     * store remote ID in federated reShare table
474
+     *
475
+     * @param $shareId
476
+     * @param $remoteId
477
+     */
478
+    public function storeRemoteId(int $shareId, string $remoteId): void {
479
+        $query = $this->dbConnection->getQueryBuilder();
480
+        $query->insert('federated_reshares')
481
+            ->values(
482
+                [
483
+                    'share_id' => $query->createNamedParameter($shareId),
484
+                    'remote_id' => $query->createNamedParameter($remoteId),
485
+                ]
486
+            );
487
+        $query->execute();
488
+    }
489
+
490
+    /**
491
+     * get share ID on remote server for federated re-shares
492
+     *
493
+     * @param IShare $share
494
+     * @return string
495
+     * @throws ShareNotFound
496
+     */
497
+    public function getRemoteId(IShare $share): string {
498
+        $query = $this->dbConnection->getQueryBuilder();
499
+        $query->select('remote_id')->from('federated_reshares')
500
+            ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
501
+        $result = $query->execute();
502
+        $data = $result->fetch();
503
+        $result->closeCursor();
504
+
505
+        if (!is_array($data) || !isset($data['remote_id'])) {
506
+            throw new ShareNotFound();
507
+        }
508
+
509
+        return (string)$data['remote_id'];
510
+    }
511
+
512
+    /**
513
+     * @inheritdoc
514
+     */
515
+    public function move(IShare $share, $recipient) {
516
+        /*
517 517
 		 * This function does nothing yet as it is just for outgoing
518 518
 		 * federated shares.
519 519
 		 */
520
-		return $share;
521
-	}
522
-
523
-	/**
524
-	 * Get all children of this share
525
-	 *
526
-	 * @param IShare $parent
527
-	 * @return IShare[]
528
-	 */
529
-	public function getChildren(IShare $parent) {
530
-		$children = [];
531
-
532
-		$qb = $this->dbConnection->getQueryBuilder();
533
-		$qb->select('*')
534
-			->from('share')
535
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
536
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
537
-			->orderBy('id');
538
-
539
-		$cursor = $qb->execute();
540
-		while ($data = $cursor->fetch()) {
541
-			$children[] = $this->createShareObject($data);
542
-		}
543
-		$cursor->closeCursor();
544
-
545
-		return $children;
546
-	}
547
-
548
-	/**
549
-	 * Delete a share (owner unShares the file)
550
-	 *
551
-	 * @param IShare $share
552
-	 * @throws ShareNotFound
553
-	 * @throws \OCP\HintException
554
-	 */
555
-	public function delete(IShare $share) {
556
-		[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedWith());
557
-
558
-		// if the local user is the owner we can send the unShare request directly...
559
-		if ($this->userManager->userExists($share->getShareOwner())) {
560
-			$this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
561
-			$this->revokeShare($share, true);
562
-		} else { // ... if not we need to correct ID for the unShare request
563
-			$remoteId = $this->getRemoteId($share);
564
-			$this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
565
-			$this->revokeShare($share, false);
566
-		}
567
-
568
-		// only remove the share when all messages are send to not lose information
569
-		// about the share to early
570
-		$this->removeShareFromTable($share);
571
-	}
572
-
573
-	/**
574
-	 * in case of a re-share we need to send the other use (initiator or owner)
575
-	 * a message that the file was unshared
576
-	 *
577
-	 * @param IShare $share
578
-	 * @param bool $isOwner the user can either be the owner or the user who re-sahred it
579
-	 * @throws ShareNotFound
580
-	 * @throws \OCP\HintException
581
-	 */
582
-	protected function revokeShare($share, $isOwner) {
583
-		if ($this->userManager->userExists($share->getShareOwner()) && $this->userManager->userExists($share->getSharedBy())) {
584
-			// If both the owner and the initiator of the share are local users we don't have to notify anybody else
585
-			return;
586
-		}
587
-
588
-		// also send a unShare request to the initiator, if this is a different user than the owner
589
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
590
-			if ($isOwner) {
591
-				[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
592
-			} else {
593
-				[, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
594
-			}
595
-			$remoteId = $this->getRemoteId($share);
596
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
597
-		}
598
-	}
599
-
600
-	/**
601
-	 * remove share from table
602
-	 *
603
-	 * @param IShare $share
604
-	 */
605
-	public function removeShareFromTable(IShare $share) {
606
-		$this->removeShareFromTableById($share->getId());
607
-	}
608
-
609
-	/**
610
-	 * remove share from table
611
-	 *
612
-	 * @param string $shareId
613
-	 */
614
-	private function removeShareFromTableById($shareId) {
615
-		$qb = $this->dbConnection->getQueryBuilder();
616
-		$qb->delete('share')
617
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)))
618
-			->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE)));
619
-		$qb->execute();
620
-
621
-		$qb->delete('federated_reshares')
622
-			->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
623
-		$qb->execute();
624
-	}
625
-
626
-	/**
627
-	 * @inheritdoc
628
-	 */
629
-	public function deleteFromSelf(IShare $share, $recipient) {
630
-		// nothing to do here. Technically deleteFromSelf in the context of federated
631
-		// shares is a umount of an external storage. This is handled here
632
-		// apps/files_sharing/lib/external/manager.php
633
-		// TODO move this code over to this app
634
-	}
635
-
636
-	public function restore(IShare $share, string $recipient): IShare {
637
-		throw new GenericShareException('not implemented');
638
-	}
639
-
640
-
641
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
642
-		$qb = $this->dbConnection->getQueryBuilder();
643
-		$qb->select('*')
644
-			->from('share', 's')
645
-			->andWhere($qb->expr()->orX(
646
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
647
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
648
-			))
649
-			->andWhere(
650
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))
651
-			);
652
-
653
-		/**
654
-		 * Reshares for this user are shares where they are the owner.
655
-		 */
656
-		if ($reshares === false) {
657
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
658
-		} else {
659
-			$qb->andWhere(
660
-				$qb->expr()->orX(
661
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
662
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
663
-				)
664
-			);
665
-		}
666
-
667
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
668
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
669
-
670
-		$qb->orderBy('id');
671
-
672
-		$cursor = $qb->execute();
673
-		$shares = [];
674
-		while ($data = $cursor->fetch()) {
675
-			$shares[$data['fileid']][] = $this->createShareObject($data);
676
-		}
677
-		$cursor->closeCursor();
678
-
679
-		return $shares;
680
-	}
681
-
682
-	/**
683
-	 * @inheritdoc
684
-	 */
685
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
686
-		$qb = $this->dbConnection->getQueryBuilder();
687
-		$qb->select('*')
688
-			->from('share');
689
-
690
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
691
-
692
-		/**
693
-		 * Reshares for this user are shares where they are the owner.
694
-		 */
695
-		if ($reshares === false) {
696
-			//Special case for old shares created via the web UI
697
-			$or1 = $qb->expr()->andX(
698
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
699
-				$qb->expr()->isNull('uid_initiator')
700
-			);
701
-
702
-			$qb->andWhere(
703
-				$qb->expr()->orX(
704
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
705
-					$or1
706
-				)
707
-			);
708
-		} else {
709
-			$qb->andWhere(
710
-				$qb->expr()->orX(
711
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
712
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
713
-				)
714
-			);
715
-		}
716
-
717
-		if ($node !== null) {
718
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
719
-		}
720
-
721
-		if ($limit !== -1) {
722
-			$qb->setMaxResults($limit);
723
-		}
724
-
725
-		$qb->setFirstResult($offset);
726
-		$qb->orderBy('id');
727
-
728
-		$cursor = $qb->execute();
729
-		$shares = [];
730
-		while ($data = $cursor->fetch()) {
731
-			$shares[] = $this->createShareObject($data);
732
-		}
733
-		$cursor->closeCursor();
734
-
735
-		return $shares;
736
-	}
737
-
738
-	/**
739
-	 * @inheritdoc
740
-	 */
741
-	public function getShareById($id, $recipientId = null) {
742
-		$qb = $this->dbConnection->getQueryBuilder();
743
-
744
-		$qb->select('*')
745
-			->from('share')
746
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
747
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
748
-
749
-		$cursor = $qb->execute();
750
-		$data = $cursor->fetch();
751
-		$cursor->closeCursor();
752
-
753
-		if ($data === false) {
754
-			throw new ShareNotFound('Can not find share with ID: ' . $id);
755
-		}
756
-
757
-		try {
758
-			$share = $this->createShareObject($data);
759
-		} catch (InvalidShare $e) {
760
-			throw new ShareNotFound();
761
-		}
762
-
763
-		return $share;
764
-	}
765
-
766
-	/**
767
-	 * Get shares for a given path
768
-	 *
769
-	 * @param \OCP\Files\Node $path
770
-	 * @return IShare[]
771
-	 */
772
-	public function getSharesByPath(Node $path) {
773
-		$qb = $this->dbConnection->getQueryBuilder();
774
-
775
-		// get federated user shares
776
-		$cursor = $qb->select('*')
777
-			->from('share')
778
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
779
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
780
-			->execute();
781
-
782
-		$shares = [];
783
-		while ($data = $cursor->fetch()) {
784
-			$shares[] = $this->createShareObject($data);
785
-		}
786
-		$cursor->closeCursor();
787
-
788
-		return $shares;
789
-	}
790
-
791
-	/**
792
-	 * @inheritdoc
793
-	 */
794
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
795
-		/** @var IShare[] $shares */
796
-		$shares = [];
797
-
798
-		//Get shares directly with this user
799
-		$qb = $this->dbConnection->getQueryBuilder();
800
-		$qb->select('*')
801
-			->from('share');
802
-
803
-		// Order by id
804
-		$qb->orderBy('id');
805
-
806
-		// Set limit and offset
807
-		if ($limit !== -1) {
808
-			$qb->setMaxResults($limit);
809
-		}
810
-		$qb->setFirstResult($offset);
811
-
812
-		$qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
813
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
814
-
815
-		// Filter by node if provided
816
-		if ($node !== null) {
817
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
818
-		}
819
-
820
-		$cursor = $qb->execute();
821
-
822
-		while ($data = $cursor->fetch()) {
823
-			$shares[] = $this->createShareObject($data);
824
-		}
825
-		$cursor->closeCursor();
826
-
827
-
828
-		return $shares;
829
-	}
830
-
831
-	/**
832
-	 * Get a share by token
833
-	 *
834
-	 * @param string $token
835
-	 * @return IShare
836
-	 * @throws ShareNotFound
837
-	 */
838
-	public function getShareByToken($token) {
839
-		$qb = $this->dbConnection->getQueryBuilder();
840
-
841
-		$cursor = $qb->select('*')
842
-			->from('share')
843
-			->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
844
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
845
-			->execute();
846
-
847
-		$data = $cursor->fetch();
848
-
849
-		if ($data === false) {
850
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
851
-		}
852
-
853
-		try {
854
-			$share = $this->createShareObject($data);
855
-		} catch (InvalidShare $e) {
856
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
857
-		}
858
-
859
-		return $share;
860
-	}
861
-
862
-	/**
863
-	 * get database row of a give share
864
-	 *
865
-	 * @param $id
866
-	 * @return array
867
-	 * @throws ShareNotFound
868
-	 */
869
-	private function getRawShare($id) {
870
-
871
-		// Now fetch the inserted share and create a complete share object
872
-		$qb = $this->dbConnection->getQueryBuilder();
873
-		$qb->select('*')
874
-			->from('share')
875
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
876
-
877
-		$cursor = $qb->execute();
878
-		$data = $cursor->fetch();
879
-		$cursor->closeCursor();
880
-
881
-		if ($data === false) {
882
-			throw new ShareNotFound;
883
-		}
884
-
885
-		return $data;
886
-	}
887
-
888
-	/**
889
-	 * Create a share object from an database row
890
-	 *
891
-	 * @param array $data
892
-	 * @return IShare
893
-	 * @throws InvalidShare
894
-	 * @throws ShareNotFound
895
-	 */
896
-	private function createShareObject($data) {
897
-		$share = new Share($this->rootFolder, $this->userManager);
898
-		$share->setId((int)$data['id'])
899
-			->setShareType((int)$data['share_type'])
900
-			->setPermissions((int)$data['permissions'])
901
-			->setTarget($data['file_target'])
902
-			->setMailSend((bool)$data['mail_send'])
903
-			->setToken($data['token']);
904
-
905
-		$shareTime = new \DateTime();
906
-		$shareTime->setTimestamp((int)$data['stime']);
907
-		$share->setShareTime($shareTime);
908
-		$share->setSharedWith($data['share_with']);
909
-
910
-		if ($data['uid_initiator'] !== null) {
911
-			$share->setShareOwner($data['uid_owner']);
912
-			$share->setSharedBy($data['uid_initiator']);
913
-		} else {
914
-			//OLD SHARE
915
-			$share->setSharedBy($data['uid_owner']);
916
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
917
-
918
-			$owner = $path->getOwner();
919
-			$share->setShareOwner($owner->getUID());
920
-		}
921
-
922
-		$share->setNodeId((int)$data['file_source']);
923
-		$share->setNodeType($data['item_type']);
924
-
925
-		$share->setProviderId($this->identifier());
926
-
927
-		if ($data['expiration'] !== null) {
928
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
929
-			$share->setExpirationDate($expiration);
930
-		}
931
-
932
-		return $share;
933
-	}
934
-
935
-	/**
936
-	 * Get the node with file $id for $user
937
-	 *
938
-	 * @param string $userId
939
-	 * @param int $id
940
-	 * @return \OCP\Files\File|\OCP\Files\Folder
941
-	 * @throws InvalidShare
942
-	 */
943
-	private function getNode($userId, $id) {
944
-		try {
945
-			$userFolder = $this->rootFolder->getUserFolder($userId);
946
-		} catch (NotFoundException $e) {
947
-			throw new InvalidShare();
948
-		}
949
-
950
-		$nodes = $userFolder->getById($id);
951
-
952
-		if (empty($nodes)) {
953
-			throw new InvalidShare();
954
-		}
955
-
956
-		return $nodes[0];
957
-	}
958
-
959
-	/**
960
-	 * A user is deleted from the system
961
-	 * So clean up the relevant shares.
962
-	 *
963
-	 * @param string $uid
964
-	 * @param int $shareType
965
-	 */
966
-	public function userDeleted($uid, $shareType) {
967
-		//TODO: probabaly a good idea to send unshare info to remote servers
968
-
969
-		$qb = $this->dbConnection->getQueryBuilder();
970
-
971
-		$qb->delete('share')
972
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
973
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
974
-			->execute();
975
-	}
976
-
977
-	/**
978
-	 * This provider does not handle groups
979
-	 *
980
-	 * @param string $gid
981
-	 */
982
-	public function groupDeleted($gid) {
983
-		// We don't handle groups here
984
-	}
985
-
986
-	/**
987
-	 * This provider does not handle groups
988
-	 *
989
-	 * @param string $uid
990
-	 * @param string $gid
991
-	 */
992
-	public function userDeletedFromGroup($uid, $gid) {
993
-		// We don't handle groups here
994
-	}
995
-
996
-	/**
997
-	 * check if users from other Nextcloud instances are allowed to mount public links share by this instance
998
-	 *
999
-	 * @return bool
1000
-	 */
1001
-	public function isOutgoingServer2serverShareEnabled() {
1002
-		if ($this->gsConfig->onlyInternalFederation()) {
1003
-			return false;
1004
-		}
1005
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
1006
-		return ($result === 'yes');
1007
-	}
1008
-
1009
-	/**
1010
-	 * check if users are allowed to mount public links from other Nextclouds
1011
-	 *
1012
-	 * @return bool
1013
-	 */
1014
-	public function isIncomingServer2serverShareEnabled() {
1015
-		if ($this->gsConfig->onlyInternalFederation()) {
1016
-			return false;
1017
-		}
1018
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
1019
-		return ($result === 'yes');
1020
-	}
1021
-
1022
-
1023
-	/**
1024
-	 * check if users from other Nextcloud instances are allowed to send federated group shares
1025
-	 *
1026
-	 * @return bool
1027
-	 */
1028
-	public function isOutgoingServer2serverGroupShareEnabled() {
1029
-		if ($this->gsConfig->onlyInternalFederation()) {
1030
-			return false;
1031
-		}
1032
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
1033
-		return ($result === 'yes');
1034
-	}
1035
-
1036
-	/**
1037
-	 * check if users are allowed to receive federated group shares
1038
-	 *
1039
-	 * @return bool
1040
-	 */
1041
-	public function isIncomingServer2serverGroupShareEnabled() {
1042
-		if ($this->gsConfig->onlyInternalFederation()) {
1043
-			return false;
1044
-		}
1045
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
1046
-		return ($result === 'yes');
1047
-	}
1048
-
1049
-	/**
1050
-	 * check if federated group sharing is supported, therefore the OCM API need to be enabled
1051
-	 *
1052
-	 * @return bool
1053
-	 */
1054
-	public function isFederatedGroupSharingSupported() {
1055
-		return $this->cloudFederationProviderManager->isReady();
1056
-	}
1057
-
1058
-	/**
1059
-	 * Check if querying sharees on the lookup server is enabled
1060
-	 *
1061
-	 * @return bool
1062
-	 */
1063
-	public function isLookupServerQueriesEnabled() {
1064
-		// in a global scale setup we should always query the lookup server
1065
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
1066
-			return true;
1067
-		}
1068
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes');
1069
-		return ($result === 'yes');
1070
-	}
1071
-
1072
-
1073
-	/**
1074
-	 * Check if it is allowed to publish user specific data to the lookup server
1075
-	 *
1076
-	 * @return bool
1077
-	 */
1078
-	public function isLookupServerUploadEnabled() {
1079
-		// in a global scale setup the admin is responsible to keep the lookup server up-to-date
1080
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
1081
-			return false;
1082
-		}
1083
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1084
-		return ($result === 'yes');
1085
-	}
1086
-
1087
-	/**
1088
-	 * @inheritdoc
1089
-	 */
1090
-	public function getAccessList($nodes, $currentAccess) {
1091
-		$ids = [];
1092
-		foreach ($nodes as $node) {
1093
-			$ids[] = $node->getId();
1094
-		}
1095
-
1096
-		$qb = $this->dbConnection->getQueryBuilder();
1097
-		$qb->select('share_with', 'token', 'file_source')
1098
-			->from('share')
1099
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
1100
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1101
-			->andWhere($qb->expr()->orX(
1102
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1103
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1104
-			));
1105
-		$cursor = $qb->execute();
1106
-
1107
-		if ($currentAccess === false) {
1108
-			$remote = $cursor->fetch() !== false;
1109
-			$cursor->closeCursor();
1110
-
1111
-			return ['remote' => $remote];
1112
-		}
1113
-
1114
-		$remote = [];
1115
-		while ($row = $cursor->fetch()) {
1116
-			$remote[$row['share_with']] = [
1117
-				'node_id' => $row['file_source'],
1118
-				'token' => $row['token'],
1119
-			];
1120
-		}
1121
-		$cursor->closeCursor();
1122
-
1123
-		return ['remote' => $remote];
1124
-	}
1125
-
1126
-	public function getAllShares(): iterable {
1127
-		$qb = $this->dbConnection->getQueryBuilder();
1128
-
1129
-		$qb->select('*')
1130
-			->from('share')
1131
-			->where(
1132
-				$qb->expr()->orX(
1133
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE)),
1134
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE_GROUP))
1135
-				)
1136
-			);
1137
-
1138
-		$cursor = $qb->execute();
1139
-		while ($data = $cursor->fetch()) {
1140
-			try {
1141
-				$share = $this->createShareObject($data);
1142
-			} catch (InvalidShare $e) {
1143
-				continue;
1144
-			} catch (ShareNotFound $e) {
1145
-				continue;
1146
-			}
1147
-
1148
-			yield $share;
1149
-		}
1150
-		$cursor->closeCursor();
1151
-	}
520
+        return $share;
521
+    }
522
+
523
+    /**
524
+     * Get all children of this share
525
+     *
526
+     * @param IShare $parent
527
+     * @return IShare[]
528
+     */
529
+    public function getChildren(IShare $parent) {
530
+        $children = [];
531
+
532
+        $qb = $this->dbConnection->getQueryBuilder();
533
+        $qb->select('*')
534
+            ->from('share')
535
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
536
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
537
+            ->orderBy('id');
538
+
539
+        $cursor = $qb->execute();
540
+        while ($data = $cursor->fetch()) {
541
+            $children[] = $this->createShareObject($data);
542
+        }
543
+        $cursor->closeCursor();
544
+
545
+        return $children;
546
+    }
547
+
548
+    /**
549
+     * Delete a share (owner unShares the file)
550
+     *
551
+     * @param IShare $share
552
+     * @throws ShareNotFound
553
+     * @throws \OCP\HintException
554
+     */
555
+    public function delete(IShare $share) {
556
+        [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedWith());
557
+
558
+        // if the local user is the owner we can send the unShare request directly...
559
+        if ($this->userManager->userExists($share->getShareOwner())) {
560
+            $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
561
+            $this->revokeShare($share, true);
562
+        } else { // ... if not we need to correct ID for the unShare request
563
+            $remoteId = $this->getRemoteId($share);
564
+            $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
565
+            $this->revokeShare($share, false);
566
+        }
567
+
568
+        // only remove the share when all messages are send to not lose information
569
+        // about the share to early
570
+        $this->removeShareFromTable($share);
571
+    }
572
+
573
+    /**
574
+     * in case of a re-share we need to send the other use (initiator or owner)
575
+     * a message that the file was unshared
576
+     *
577
+     * @param IShare $share
578
+     * @param bool $isOwner the user can either be the owner or the user who re-sahred it
579
+     * @throws ShareNotFound
580
+     * @throws \OCP\HintException
581
+     */
582
+    protected function revokeShare($share, $isOwner) {
583
+        if ($this->userManager->userExists($share->getShareOwner()) && $this->userManager->userExists($share->getSharedBy())) {
584
+            // If both the owner and the initiator of the share are local users we don't have to notify anybody else
585
+            return;
586
+        }
587
+
588
+        // also send a unShare request to the initiator, if this is a different user than the owner
589
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
590
+            if ($isOwner) {
591
+                [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
592
+            } else {
593
+                [, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
594
+            }
595
+            $remoteId = $this->getRemoteId($share);
596
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
597
+        }
598
+    }
599
+
600
+    /**
601
+     * remove share from table
602
+     *
603
+     * @param IShare $share
604
+     */
605
+    public function removeShareFromTable(IShare $share) {
606
+        $this->removeShareFromTableById($share->getId());
607
+    }
608
+
609
+    /**
610
+     * remove share from table
611
+     *
612
+     * @param string $shareId
613
+     */
614
+    private function removeShareFromTableById($shareId) {
615
+        $qb = $this->dbConnection->getQueryBuilder();
616
+        $qb->delete('share')
617
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)))
618
+            ->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE)));
619
+        $qb->execute();
620
+
621
+        $qb->delete('federated_reshares')
622
+            ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
623
+        $qb->execute();
624
+    }
625
+
626
+    /**
627
+     * @inheritdoc
628
+     */
629
+    public function deleteFromSelf(IShare $share, $recipient) {
630
+        // nothing to do here. Technically deleteFromSelf in the context of federated
631
+        // shares is a umount of an external storage. This is handled here
632
+        // apps/files_sharing/lib/external/manager.php
633
+        // TODO move this code over to this app
634
+    }
635
+
636
+    public function restore(IShare $share, string $recipient): IShare {
637
+        throw new GenericShareException('not implemented');
638
+    }
639
+
640
+
641
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
642
+        $qb = $this->dbConnection->getQueryBuilder();
643
+        $qb->select('*')
644
+            ->from('share', 's')
645
+            ->andWhere($qb->expr()->orX(
646
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
647
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
648
+            ))
649
+            ->andWhere(
650
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))
651
+            );
652
+
653
+        /**
654
+         * Reshares for this user are shares where they are the owner.
655
+         */
656
+        if ($reshares === false) {
657
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
658
+        } else {
659
+            $qb->andWhere(
660
+                $qb->expr()->orX(
661
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
662
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
663
+                )
664
+            );
665
+        }
666
+
667
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
668
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
669
+
670
+        $qb->orderBy('id');
671
+
672
+        $cursor = $qb->execute();
673
+        $shares = [];
674
+        while ($data = $cursor->fetch()) {
675
+            $shares[$data['fileid']][] = $this->createShareObject($data);
676
+        }
677
+        $cursor->closeCursor();
678
+
679
+        return $shares;
680
+    }
681
+
682
+    /**
683
+     * @inheritdoc
684
+     */
685
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
686
+        $qb = $this->dbConnection->getQueryBuilder();
687
+        $qb->select('*')
688
+            ->from('share');
689
+
690
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
691
+
692
+        /**
693
+         * Reshares for this user are shares where they are the owner.
694
+         */
695
+        if ($reshares === false) {
696
+            //Special case for old shares created via the web UI
697
+            $or1 = $qb->expr()->andX(
698
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
699
+                $qb->expr()->isNull('uid_initiator')
700
+            );
701
+
702
+            $qb->andWhere(
703
+                $qb->expr()->orX(
704
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
705
+                    $or1
706
+                )
707
+            );
708
+        } else {
709
+            $qb->andWhere(
710
+                $qb->expr()->orX(
711
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
712
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
713
+                )
714
+            );
715
+        }
716
+
717
+        if ($node !== null) {
718
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
719
+        }
720
+
721
+        if ($limit !== -1) {
722
+            $qb->setMaxResults($limit);
723
+        }
724
+
725
+        $qb->setFirstResult($offset);
726
+        $qb->orderBy('id');
727
+
728
+        $cursor = $qb->execute();
729
+        $shares = [];
730
+        while ($data = $cursor->fetch()) {
731
+            $shares[] = $this->createShareObject($data);
732
+        }
733
+        $cursor->closeCursor();
734
+
735
+        return $shares;
736
+    }
737
+
738
+    /**
739
+     * @inheritdoc
740
+     */
741
+    public function getShareById($id, $recipientId = null) {
742
+        $qb = $this->dbConnection->getQueryBuilder();
743
+
744
+        $qb->select('*')
745
+            ->from('share')
746
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
747
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
748
+
749
+        $cursor = $qb->execute();
750
+        $data = $cursor->fetch();
751
+        $cursor->closeCursor();
752
+
753
+        if ($data === false) {
754
+            throw new ShareNotFound('Can not find share with ID: ' . $id);
755
+        }
756
+
757
+        try {
758
+            $share = $this->createShareObject($data);
759
+        } catch (InvalidShare $e) {
760
+            throw new ShareNotFound();
761
+        }
762
+
763
+        return $share;
764
+    }
765
+
766
+    /**
767
+     * Get shares for a given path
768
+     *
769
+     * @param \OCP\Files\Node $path
770
+     * @return IShare[]
771
+     */
772
+    public function getSharesByPath(Node $path) {
773
+        $qb = $this->dbConnection->getQueryBuilder();
774
+
775
+        // get federated user shares
776
+        $cursor = $qb->select('*')
777
+            ->from('share')
778
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
779
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
780
+            ->execute();
781
+
782
+        $shares = [];
783
+        while ($data = $cursor->fetch()) {
784
+            $shares[] = $this->createShareObject($data);
785
+        }
786
+        $cursor->closeCursor();
787
+
788
+        return $shares;
789
+    }
790
+
791
+    /**
792
+     * @inheritdoc
793
+     */
794
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
795
+        /** @var IShare[] $shares */
796
+        $shares = [];
797
+
798
+        //Get shares directly with this user
799
+        $qb = $this->dbConnection->getQueryBuilder();
800
+        $qb->select('*')
801
+            ->from('share');
802
+
803
+        // Order by id
804
+        $qb->orderBy('id');
805
+
806
+        // Set limit and offset
807
+        if ($limit !== -1) {
808
+            $qb->setMaxResults($limit);
809
+        }
810
+        $qb->setFirstResult($offset);
811
+
812
+        $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
813
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
814
+
815
+        // Filter by node if provided
816
+        if ($node !== null) {
817
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
818
+        }
819
+
820
+        $cursor = $qb->execute();
821
+
822
+        while ($data = $cursor->fetch()) {
823
+            $shares[] = $this->createShareObject($data);
824
+        }
825
+        $cursor->closeCursor();
826
+
827
+
828
+        return $shares;
829
+    }
830
+
831
+    /**
832
+     * Get a share by token
833
+     *
834
+     * @param string $token
835
+     * @return IShare
836
+     * @throws ShareNotFound
837
+     */
838
+    public function getShareByToken($token) {
839
+        $qb = $this->dbConnection->getQueryBuilder();
840
+
841
+        $cursor = $qb->select('*')
842
+            ->from('share')
843
+            ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
844
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
845
+            ->execute();
846
+
847
+        $data = $cursor->fetch();
848
+
849
+        if ($data === false) {
850
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
851
+        }
852
+
853
+        try {
854
+            $share = $this->createShareObject($data);
855
+        } catch (InvalidShare $e) {
856
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
857
+        }
858
+
859
+        return $share;
860
+    }
861
+
862
+    /**
863
+     * get database row of a give share
864
+     *
865
+     * @param $id
866
+     * @return array
867
+     * @throws ShareNotFound
868
+     */
869
+    private function getRawShare($id) {
870
+
871
+        // Now fetch the inserted share and create a complete share object
872
+        $qb = $this->dbConnection->getQueryBuilder();
873
+        $qb->select('*')
874
+            ->from('share')
875
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
876
+
877
+        $cursor = $qb->execute();
878
+        $data = $cursor->fetch();
879
+        $cursor->closeCursor();
880
+
881
+        if ($data === false) {
882
+            throw new ShareNotFound;
883
+        }
884
+
885
+        return $data;
886
+    }
887
+
888
+    /**
889
+     * Create a share object from an database row
890
+     *
891
+     * @param array $data
892
+     * @return IShare
893
+     * @throws InvalidShare
894
+     * @throws ShareNotFound
895
+     */
896
+    private function createShareObject($data) {
897
+        $share = new Share($this->rootFolder, $this->userManager);
898
+        $share->setId((int)$data['id'])
899
+            ->setShareType((int)$data['share_type'])
900
+            ->setPermissions((int)$data['permissions'])
901
+            ->setTarget($data['file_target'])
902
+            ->setMailSend((bool)$data['mail_send'])
903
+            ->setToken($data['token']);
904
+
905
+        $shareTime = new \DateTime();
906
+        $shareTime->setTimestamp((int)$data['stime']);
907
+        $share->setShareTime($shareTime);
908
+        $share->setSharedWith($data['share_with']);
909
+
910
+        if ($data['uid_initiator'] !== null) {
911
+            $share->setShareOwner($data['uid_owner']);
912
+            $share->setSharedBy($data['uid_initiator']);
913
+        } else {
914
+            //OLD SHARE
915
+            $share->setSharedBy($data['uid_owner']);
916
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
917
+
918
+            $owner = $path->getOwner();
919
+            $share->setShareOwner($owner->getUID());
920
+        }
921
+
922
+        $share->setNodeId((int)$data['file_source']);
923
+        $share->setNodeType($data['item_type']);
924
+
925
+        $share->setProviderId($this->identifier());
926
+
927
+        if ($data['expiration'] !== null) {
928
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
929
+            $share->setExpirationDate($expiration);
930
+        }
931
+
932
+        return $share;
933
+    }
934
+
935
+    /**
936
+     * Get the node with file $id for $user
937
+     *
938
+     * @param string $userId
939
+     * @param int $id
940
+     * @return \OCP\Files\File|\OCP\Files\Folder
941
+     * @throws InvalidShare
942
+     */
943
+    private function getNode($userId, $id) {
944
+        try {
945
+            $userFolder = $this->rootFolder->getUserFolder($userId);
946
+        } catch (NotFoundException $e) {
947
+            throw new InvalidShare();
948
+        }
949
+
950
+        $nodes = $userFolder->getById($id);
951
+
952
+        if (empty($nodes)) {
953
+            throw new InvalidShare();
954
+        }
955
+
956
+        return $nodes[0];
957
+    }
958
+
959
+    /**
960
+     * A user is deleted from the system
961
+     * So clean up the relevant shares.
962
+     *
963
+     * @param string $uid
964
+     * @param int $shareType
965
+     */
966
+    public function userDeleted($uid, $shareType) {
967
+        //TODO: probabaly a good idea to send unshare info to remote servers
968
+
969
+        $qb = $this->dbConnection->getQueryBuilder();
970
+
971
+        $qb->delete('share')
972
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
973
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
974
+            ->execute();
975
+    }
976
+
977
+    /**
978
+     * This provider does not handle groups
979
+     *
980
+     * @param string $gid
981
+     */
982
+    public function groupDeleted($gid) {
983
+        // We don't handle groups here
984
+    }
985
+
986
+    /**
987
+     * This provider does not handle groups
988
+     *
989
+     * @param string $uid
990
+     * @param string $gid
991
+     */
992
+    public function userDeletedFromGroup($uid, $gid) {
993
+        // We don't handle groups here
994
+    }
995
+
996
+    /**
997
+     * check if users from other Nextcloud instances are allowed to mount public links share by this instance
998
+     *
999
+     * @return bool
1000
+     */
1001
+    public function isOutgoingServer2serverShareEnabled() {
1002
+        if ($this->gsConfig->onlyInternalFederation()) {
1003
+            return false;
1004
+        }
1005
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
1006
+        return ($result === 'yes');
1007
+    }
1008
+
1009
+    /**
1010
+     * check if users are allowed to mount public links from other Nextclouds
1011
+     *
1012
+     * @return bool
1013
+     */
1014
+    public function isIncomingServer2serverShareEnabled() {
1015
+        if ($this->gsConfig->onlyInternalFederation()) {
1016
+            return false;
1017
+        }
1018
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
1019
+        return ($result === 'yes');
1020
+    }
1021
+
1022
+
1023
+    /**
1024
+     * check if users from other Nextcloud instances are allowed to send federated group shares
1025
+     *
1026
+     * @return bool
1027
+     */
1028
+    public function isOutgoingServer2serverGroupShareEnabled() {
1029
+        if ($this->gsConfig->onlyInternalFederation()) {
1030
+            return false;
1031
+        }
1032
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
1033
+        return ($result === 'yes');
1034
+    }
1035
+
1036
+    /**
1037
+     * check if users are allowed to receive federated group shares
1038
+     *
1039
+     * @return bool
1040
+     */
1041
+    public function isIncomingServer2serverGroupShareEnabled() {
1042
+        if ($this->gsConfig->onlyInternalFederation()) {
1043
+            return false;
1044
+        }
1045
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
1046
+        return ($result === 'yes');
1047
+    }
1048
+
1049
+    /**
1050
+     * check if federated group sharing is supported, therefore the OCM API need to be enabled
1051
+     *
1052
+     * @return bool
1053
+     */
1054
+    public function isFederatedGroupSharingSupported() {
1055
+        return $this->cloudFederationProviderManager->isReady();
1056
+    }
1057
+
1058
+    /**
1059
+     * Check if querying sharees on the lookup server is enabled
1060
+     *
1061
+     * @return bool
1062
+     */
1063
+    public function isLookupServerQueriesEnabled() {
1064
+        // in a global scale setup we should always query the lookup server
1065
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
1066
+            return true;
1067
+        }
1068
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes');
1069
+        return ($result === 'yes');
1070
+    }
1071
+
1072
+
1073
+    /**
1074
+     * Check if it is allowed to publish user specific data to the lookup server
1075
+     *
1076
+     * @return bool
1077
+     */
1078
+    public function isLookupServerUploadEnabled() {
1079
+        // in a global scale setup the admin is responsible to keep the lookup server up-to-date
1080
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
1081
+            return false;
1082
+        }
1083
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1084
+        return ($result === 'yes');
1085
+    }
1086
+
1087
+    /**
1088
+     * @inheritdoc
1089
+     */
1090
+    public function getAccessList($nodes, $currentAccess) {
1091
+        $ids = [];
1092
+        foreach ($nodes as $node) {
1093
+            $ids[] = $node->getId();
1094
+        }
1095
+
1096
+        $qb = $this->dbConnection->getQueryBuilder();
1097
+        $qb->select('share_with', 'token', 'file_source')
1098
+            ->from('share')
1099
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
1100
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1101
+            ->andWhere($qb->expr()->orX(
1102
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1103
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1104
+            ));
1105
+        $cursor = $qb->execute();
1106
+
1107
+        if ($currentAccess === false) {
1108
+            $remote = $cursor->fetch() !== false;
1109
+            $cursor->closeCursor();
1110
+
1111
+            return ['remote' => $remote];
1112
+        }
1113
+
1114
+        $remote = [];
1115
+        while ($row = $cursor->fetch()) {
1116
+            $remote[$row['share_with']] = [
1117
+                'node_id' => $row['file_source'],
1118
+                'token' => $row['token'],
1119
+            ];
1120
+        }
1121
+        $cursor->closeCursor();
1122
+
1123
+        return ['remote' => $remote];
1124
+    }
1125
+
1126
+    public function getAllShares(): iterable {
1127
+        $qb = $this->dbConnection->getQueryBuilder();
1128
+
1129
+        $qb->select('*')
1130
+            ->from('share')
1131
+            ->where(
1132
+                $qb->expr()->orX(
1133
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE)),
1134
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE_GROUP))
1135
+                )
1136
+            );
1137
+
1138
+        $cursor = $qb->execute();
1139
+        while ($data = $cursor->fetch()) {
1140
+            try {
1141
+                $share = $this->createShareObject($data);
1142
+            } catch (InvalidShare $e) {
1143
+                continue;
1144
+            } catch (ShareNotFound $e) {
1145
+                continue;
1146
+            }
1147
+
1148
+            yield $share;
1149
+        }
1150
+        $cursor->closeCursor();
1151
+    }
1152 1152
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php 1 patch
Indentation   +769 added lines, -769 removed lines patch added patch discarded remove patch
@@ -62,773 +62,773 @@
 block discarded – undo
62 62
 
63 63
 class CloudFederationProviderFiles implements ICloudFederationProvider {
64 64
 
65
-	/** @var IAppManager */
66
-	private $appManager;
67
-
68
-	/** @var FederatedShareProvider */
69
-	private $federatedShareProvider;
70
-
71
-	/** @var AddressHandler */
72
-	private $addressHandler;
73
-
74
-	/** @var ILogger */
75
-	private $logger;
76
-
77
-	/** @var IUserManager */
78
-	private $userManager;
79
-
80
-	/** @var IManager */
81
-	private $shareManager;
82
-
83
-	/** @var ICloudIdManager */
84
-	private $cloudIdManager;
85
-
86
-	/** @var IActivityManager */
87
-	private $activityManager;
88
-
89
-	/** @var INotificationManager */
90
-	private $notificationManager;
91
-
92
-	/** @var IURLGenerator */
93
-	private $urlGenerator;
94
-
95
-	/** @var ICloudFederationFactory */
96
-	private $cloudFederationFactory;
97
-
98
-	/** @var ICloudFederationProviderManager */
99
-	private $cloudFederationProviderManager;
100
-
101
-	/** @var IDBConnection */
102
-	private $connection;
103
-
104
-	/** @var IGroupManager */
105
-	private $groupManager;
106
-
107
-	/** @var IConfig */
108
-	private $config;
109
-
110
-	/**
111
-	 * CloudFederationProvider constructor.
112
-	 *
113
-	 * @param IAppManager $appManager
114
-	 * @param FederatedShareProvider $federatedShareProvider
115
-	 * @param AddressHandler $addressHandler
116
-	 * @param ILogger $logger
117
-	 * @param IUserManager $userManager
118
-	 * @param IManager $shareManager
119
-	 * @param ICloudIdManager $cloudIdManager
120
-	 * @param IActivityManager $activityManager
121
-	 * @param INotificationManager $notificationManager
122
-	 * @param IURLGenerator $urlGenerator
123
-	 * @param ICloudFederationFactory $cloudFederationFactory
124
-	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
125
-	 * @param IDBConnection $connection
126
-	 * @param IGroupManager $groupManager
127
-	 */
128
-	public function __construct(IAppManager $appManager,
129
-								FederatedShareProvider $federatedShareProvider,
130
-								AddressHandler $addressHandler,
131
-								ILogger $logger,
132
-								IUserManager $userManager,
133
-								IManager $shareManager,
134
-								ICloudIdManager $cloudIdManager,
135
-								IActivityManager $activityManager,
136
-								INotificationManager $notificationManager,
137
-								IURLGenerator $urlGenerator,
138
-								ICloudFederationFactory $cloudFederationFactory,
139
-								ICloudFederationProviderManager $cloudFederationProviderManager,
140
-								IDBConnection $connection,
141
-								IGroupManager $groupManager,
142
-								IConfig $config
143
-	) {
144
-		$this->appManager = $appManager;
145
-		$this->federatedShareProvider = $federatedShareProvider;
146
-		$this->addressHandler = $addressHandler;
147
-		$this->logger = $logger;
148
-		$this->userManager = $userManager;
149
-		$this->shareManager = $shareManager;
150
-		$this->cloudIdManager = $cloudIdManager;
151
-		$this->activityManager = $activityManager;
152
-		$this->notificationManager = $notificationManager;
153
-		$this->urlGenerator = $urlGenerator;
154
-		$this->cloudFederationFactory = $cloudFederationFactory;
155
-		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
156
-		$this->connection = $connection;
157
-		$this->groupManager = $groupManager;
158
-		$this->config = $config;
159
-	}
160
-
161
-
162
-
163
-	/**
164
-	 * @return string
165
-	 */
166
-	public function getShareType() {
167
-		return 'file';
168
-	}
169
-
170
-	/**
171
-	 * share received from another server
172
-	 *
173
-	 * @param ICloudFederationShare $share
174
-	 * @return string provider specific unique ID of the share
175
-	 *
176
-	 * @throws ProviderCouldNotAddShareException
177
-	 * @throws \OCP\AppFramework\QueryException
178
-	 * @throws HintException
179
-	 * @since 14.0.0
180
-	 */
181
-	public function shareReceived(ICloudFederationShare $share) {
182
-		if (!$this->isS2SEnabled(true)) {
183
-			throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
184
-		}
185
-
186
-		$protocol = $share->getProtocol();
187
-		if ($protocol['name'] !== 'webdav') {
188
-			throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
189
-		}
190
-
191
-		[$ownerUid, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
192
-		// for backward compatibility make sure that the remote url stored in the
193
-		// database ends with a trailing slash
194
-		if (substr($remote, -1) !== '/') {
195
-			$remote = $remote . '/';
196
-		}
197
-
198
-		$token = $share->getShareSecret();
199
-		$name = $share->getResourceName();
200
-		$owner = $share->getOwnerDisplayName();
201
-		$sharedBy = $share->getSharedByDisplayName();
202
-		$shareWith = $share->getShareWith();
203
-		$remoteId = $share->getProviderId();
204
-		$sharedByFederatedId = $share->getSharedBy();
205
-		$ownerFederatedId = $share->getOwner();
206
-		$shareType = $this->mapShareTypeToNextcloud($share->getShareType());
207
-
208
-		// if no explicit information about the person who created the share was send
209
-		// we assume that the share comes from the owner
210
-		if ($sharedByFederatedId === null) {
211
-			$sharedBy = $owner;
212
-			$sharedByFederatedId = $ownerFederatedId;
213
-		}
214
-
215
-		if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
216
-			if (!Util::isValidFileName($name)) {
217
-				throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
218
-			}
219
-
220
-			// FIXME this should be a method in the user management instead
221
-			if ($shareType === IShare::TYPE_USER) {
222
-				$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
223
-				Util::emitHook(
224
-					'\OCA\Files_Sharing\API\Server2Server',
225
-					'preLoginNameUsedAsUserName',
226
-					['uid' => &$shareWith]
227
-				);
228
-				$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
229
-
230
-				if (!$this->userManager->userExists($shareWith)) {
231
-					throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST);
232
-				}
233
-
234
-				\OC_Util::setupFS($shareWith);
235
-			}
236
-
237
-			if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
238
-				throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST);
239
-			}
240
-
241
-			$externalManager = new \OCA\Files_Sharing\External\Manager(
242
-				\OC::$server->getDatabaseConnection(),
243
-				Filesystem::getMountManager(),
244
-				Filesystem::getLoader(),
245
-				\OC::$server->getHTTPClientService(),
246
-				\OC::$server->getNotificationManager(),
247
-				\OC::$server->query(\OCP\OCS\IDiscoveryService::class),
248
-				\OC::$server->getCloudFederationProviderManager(),
249
-				\OC::$server->getCloudFederationFactory(),
250
-				\OC::$server->getGroupManager(),
251
-				\OC::$server->getUserManager(),
252
-				$shareWith,
253
-				\OC::$server->query(IEventDispatcher::class)
254
-			);
255
-
256
-			try {
257
-				$externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId);
258
-				$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
259
-
260
-				if ($shareType === IShare::TYPE_USER) {
261
-					$event = $this->activityManager->generateEvent();
262
-					$event->setApp('files_sharing')
263
-						->setType('remote_share')
264
-						->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
265
-						->setAffectedUser($shareWith)
266
-						->setObject('remote_share', $shareId, $name);
267
-					\OC::$server->getActivityManager()->publish($event);
268
-					$this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
269
-				} else {
270
-					$groupMembers = $this->groupManager->get($shareWith)->getUsers();
271
-					foreach ($groupMembers as $user) {
272
-						$event = $this->activityManager->generateEvent();
273
-						$event->setApp('files_sharing')
274
-							->setType('remote_share')
275
-							->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
276
-							->setAffectedUser($user->getUID())
277
-							->setObject('remote_share', $shareId, $name);
278
-						\OC::$server->getActivityManager()->publish($event);
279
-						$this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
280
-					}
281
-				}
282
-				return $shareId;
283
-			} catch (\Exception $e) {
284
-				$this->logger->logException($e, [
285
-					'message' => 'Server can not add remote share.',
286
-					'level' => ILogger::ERROR,
287
-					'app' => 'files_sharing'
288
-				]);
289
-				throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
290
-			}
291
-		}
292
-
293
-		throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
294
-	}
295
-
296
-	/**
297
-	 * notification received from another server
298
-	 *
299
-	 * @param string $notificationType (e.g. SHARE_ACCEPTED)
300
-	 * @param string $providerId id of the share
301
-	 * @param array $notification payload of the notification
302
-	 * @return array data send back to the sender
303
-	 *
304
-	 * @throws ActionNotSupportedException
305
-	 * @throws AuthenticationFailedException
306
-	 * @throws BadRequestException
307
-	 * @throws HintException
308
-	 * @since 14.0.0
309
-	 */
310
-	public function notificationReceived($notificationType, $providerId, array $notification) {
311
-		switch ($notificationType) {
312
-			case 'SHARE_ACCEPTED':
313
-				return $this->shareAccepted($providerId, $notification);
314
-			case 'SHARE_DECLINED':
315
-				return $this->shareDeclined($providerId, $notification);
316
-			case 'SHARE_UNSHARED':
317
-				return $this->unshare($providerId, $notification);
318
-			case 'REQUEST_RESHARE':
319
-				return $this->reshareRequested($providerId, $notification);
320
-			case 'RESHARE_UNDO':
321
-				return $this->undoReshare($providerId, $notification);
322
-			case 'RESHARE_CHANGE_PERMISSION':
323
-				return $this->updateResharePermissions($providerId, $notification);
324
-		}
325
-
326
-
327
-		throw new BadRequestException([$notificationType]);
328
-	}
329
-
330
-	/**
331
-	 * map OCM share type (strings) to Nextcloud internal share types (integer)
332
-	 *
333
-	 * @param string $shareType
334
-	 * @return int
335
-	 */
336
-	private function mapShareTypeToNextcloud($shareType) {
337
-		$result = IShare::TYPE_USER;
338
-		if ($shareType === 'group') {
339
-			$result = IShare::TYPE_GROUP;
340
-		}
341
-
342
-		return $result;
343
-	}
344
-
345
-	private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name): void {
346
-		$notification = $this->notificationManager->createNotification();
347
-		$notification->setApp('files_sharing')
348
-			->setUser($shareWith)
349
-			->setDateTime(new \DateTime())
350
-			->setObject('remote_share', $shareId)
351
-			->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
352
-
353
-		$declineAction = $notification->createAction();
354
-		$declineAction->setLabel('decline')
355
-			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
356
-		$notification->addAction($declineAction);
357
-
358
-		$acceptAction = $notification->createAction();
359
-		$acceptAction->setLabel('accept')
360
-			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
361
-		$notification->addAction($acceptAction);
362
-
363
-		$this->notificationManager->notify($notification);
364
-	}
365
-
366
-	/**
367
-	 * process notification that the recipient accepted a share
368
-	 *
369
-	 * @param string $id
370
-	 * @param array $notification
371
-	 * @return array
372
-	 * @throws ActionNotSupportedException
373
-	 * @throws AuthenticationFailedException
374
-	 * @throws BadRequestException
375
-	 * @throws HintException
376
-	 */
377
-	private function shareAccepted($id, array $notification) {
378
-		if (!$this->isS2SEnabled()) {
379
-			throw new ActionNotSupportedException('Server does not support federated cloud sharing');
380
-		}
381
-
382
-		if (!isset($notification['sharedSecret'])) {
383
-			throw new BadRequestException(['sharedSecret']);
384
-		}
385
-
386
-		$token = $notification['sharedSecret'];
387
-
388
-		$share = $this->federatedShareProvider->getShareById($id);
389
-
390
-		$this->verifyShare($share, $token);
391
-		$this->executeAcceptShare($share);
392
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
393
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
394
-			$remoteId = $this->federatedShareProvider->getRemoteId($share);
395
-			$notification = $this->cloudFederationFactory->getCloudFederationNotification();
396
-			$notification->setMessage(
397
-				'SHARE_ACCEPTED',
398
-				'file',
399
-				$remoteId,
400
-				[
401
-					'sharedSecret' => $token,
402
-					'message' => 'Recipient accepted the re-share'
403
-				]
404
-
405
-			);
406
-			$this->cloudFederationProviderManager->sendNotification($remote, $notification);
407
-		}
408
-
409
-		return [];
410
-	}
411
-
412
-	/**
413
-	 * @param IShare $share
414
-	 * @throws ShareNotFound
415
-	 */
416
-	protected function executeAcceptShare(IShare $share) {
417
-		try {
418
-			$fileId = (int)$share->getNode()->getId();
419
-			[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
420
-		} catch (\Exception $e) {
421
-			throw new ShareNotFound();
422
-		}
423
-
424
-		$event = $this->activityManager->generateEvent();
425
-		$event->setApp('files_sharing')
426
-			->setType('remote_share')
427
-			->setAffectedUser($this->getCorrectUid($share))
428
-			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
429
-			->setObject('files', $fileId, $file)
430
-			->setLink($link);
431
-		$this->activityManager->publish($event);
432
-	}
433
-
434
-	/**
435
-	 * process notification that the recipient declined a share
436
-	 *
437
-	 * @param string $id
438
-	 * @param array $notification
439
-	 * @return array
440
-	 * @throws ActionNotSupportedException
441
-	 * @throws AuthenticationFailedException
442
-	 * @throws BadRequestException
443
-	 * @throws ShareNotFound
444
-	 * @throws HintException
445
-	 *
446
-	 */
447
-	protected function shareDeclined($id, array $notification) {
448
-		if (!$this->isS2SEnabled()) {
449
-			throw new ActionNotSupportedException('Server does not support federated cloud sharing');
450
-		}
451
-
452
-		if (!isset($notification['sharedSecret'])) {
453
-			throw new BadRequestException(['sharedSecret']);
454
-		}
455
-
456
-		$token = $notification['sharedSecret'];
457
-
458
-		$share = $this->federatedShareProvider->getShareById($id);
459
-
460
-		$this->verifyShare($share, $token);
461
-
462
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
463
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
464
-			$remoteId = $this->federatedShareProvider->getRemoteId($share);
465
-			$notification = $this->cloudFederationFactory->getCloudFederationNotification();
466
-			$notification->setMessage(
467
-				'SHARE_DECLINED',
468
-				'file',
469
-				$remoteId,
470
-				[
471
-					'sharedSecret' => $token,
472
-					'message' => 'Recipient declined the re-share'
473
-				]
474
-
475
-			);
476
-			$this->cloudFederationProviderManager->sendNotification($remote, $notification);
477
-		}
478
-
479
-		$this->executeDeclineShare($share);
480
-
481
-		return [];
482
-	}
483
-
484
-	/**
485
-	 * delete declined share and create a activity
486
-	 *
487
-	 * @param IShare $share
488
-	 * @throws ShareNotFound
489
-	 */
490
-	protected function executeDeclineShare(IShare $share) {
491
-		$this->federatedShareProvider->removeShareFromTable($share);
492
-
493
-		try {
494
-			$fileId = (int)$share->getNode()->getId();
495
-			[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
496
-		} catch (\Exception $e) {
497
-			throw new ShareNotFound();
498
-		}
499
-
500
-		$event = $this->activityManager->generateEvent();
501
-		$event->setApp('files_sharing')
502
-			->setType('remote_share')
503
-			->setAffectedUser($this->getCorrectUid($share))
504
-			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
505
-			->setObject('files', $fileId, $file)
506
-			->setLink($link);
507
-		$this->activityManager->publish($event);
508
-	}
509
-
510
-	/**
511
-	 * received the notification that the owner unshared a file from you
512
-	 *
513
-	 * @param string $id
514
-	 * @param array $notification
515
-	 * @return array
516
-	 * @throws AuthenticationFailedException
517
-	 * @throws BadRequestException
518
-	 */
519
-	private function undoReshare($id, array $notification) {
520
-		if (!isset($notification['sharedSecret'])) {
521
-			throw new BadRequestException(['sharedSecret']);
522
-		}
523
-		$token = $notification['sharedSecret'];
524
-
525
-		$share = $this->federatedShareProvider->getShareById($id);
526
-
527
-		$this->verifyShare($share, $token);
528
-		$this->federatedShareProvider->removeShareFromTable($share);
529
-		return [];
530
-	}
531
-
532
-	/**
533
-	 * unshare file from self
534
-	 *
535
-	 * @param string $id
536
-	 * @param array $notification
537
-	 * @return array
538
-	 * @throws ActionNotSupportedException
539
-	 * @throws BadRequestException
540
-	 */
541
-	private function unshare($id, array $notification) {
542
-		if (!$this->isS2SEnabled(true)) {
543
-			throw new ActionNotSupportedException("incoming shares disabled!");
544
-		}
545
-
546
-		if (!isset($notification['sharedSecret'])) {
547
-			throw new BadRequestException(['sharedSecret']);
548
-		}
549
-		$token = $notification['sharedSecret'];
550
-
551
-		$qb = $this->connection->getQueryBuilder();
552
-		$qb->select('*')
553
-			->from('share_external')
554
-			->where(
555
-				$qb->expr()->andX(
556
-					$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
557
-					$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
558
-				)
559
-			);
560
-
561
-		$result = $qb->execute();
562
-		$share = $result->fetch();
563
-		$result->closeCursor();
564
-
565
-		if ($token && $id && !empty($share)) {
566
-			$remote = $this->cleanupRemote($share['remote']);
567
-
568
-			$owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
569
-			$mountpoint = $share['mountpoint'];
570
-			$user = $share['user'];
571
-
572
-			$qb = $this->connection->getQueryBuilder();
573
-			$qb->delete('share_external')
574
-				->where(
575
-					$qb->expr()->andX(
576
-						$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
577
-						$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
578
-					)
579
-				);
580
-
581
-			$qb->execute();
582
-
583
-			// delete all child in case of a group share
584
-			$qb = $this->connection->getQueryBuilder();
585
-			$qb->delete('share_external')
586
-				->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
587
-			$qb->execute();
588
-
589
-			if ((int)$share['share_type'] === IShare::TYPE_USER) {
590
-				if ($share['accepted']) {
591
-					$path = trim($mountpoint, '/');
592
-				} else {
593
-					$path = trim($share['name'], '/');
594
-				}
595
-				$notification = $this->notificationManager->createNotification();
596
-				$notification->setApp('files_sharing')
597
-					->setUser($share['user'])
598
-					->setObject('remote_share', (int)$share['id']);
599
-				$this->notificationManager->markProcessed($notification);
600
-
601
-				$event = $this->activityManager->generateEvent();
602
-				$event->setApp('files_sharing')
603
-					->setType('remote_share')
604
-					->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
605
-					->setAffectedUser($user)
606
-					->setObject('remote_share', (int)$share['id'], $path);
607
-				\OC::$server->getActivityManager()->publish($event);
608
-			}
609
-		}
610
-
611
-		return [];
612
-	}
613
-
614
-	private function cleanupRemote($remote) {
615
-		$remote = substr($remote, strpos($remote, '://') + 3);
616
-
617
-		return rtrim($remote, '/');
618
-	}
619
-
620
-	/**
621
-	 * recipient of a share request to re-share the file with another user
622
-	 *
623
-	 * @param string $id
624
-	 * @param array $notification
625
-	 * @return array
626
-	 * @throws AuthenticationFailedException
627
-	 * @throws BadRequestException
628
-	 * @throws ProviderCouldNotAddShareException
629
-	 * @throws ShareNotFound
630
-	 */
631
-	protected function reshareRequested($id, array $notification) {
632
-		if (!isset($notification['sharedSecret'])) {
633
-			throw new BadRequestException(['sharedSecret']);
634
-		}
635
-		$token = $notification['sharedSecret'];
636
-
637
-		if (!isset($notification['shareWith'])) {
638
-			throw new BadRequestException(['shareWith']);
639
-		}
640
-		$shareWith = $notification['shareWith'];
641
-
642
-		if (!isset($notification['senderId'])) {
643
-			throw new BadRequestException(['senderId']);
644
-		}
645
-		$senderId = $notification['senderId'];
646
-
647
-		$share = $this->federatedShareProvider->getShareById($id);
648
-
649
-		// We have to respect the default share permissions
650
-		$permissions = $share->getPermissions() & (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
651
-		$share->setPermissions($permissions);
652
-
653
-		// don't allow to share a file back to the owner
654
-		try {
655
-			[$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
656
-			$owner = $share->getShareOwner();
657
-			$currentServer = $this->addressHandler->generateRemoteURL();
658
-			if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
659
-				throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
660
-			}
661
-		} catch (\Exception $e) {
662
-			throw new ProviderCouldNotAddShareException($e->getMessage());
663
-		}
664
-
665
-		$this->verifyShare($share, $token);
666
-
667
-		// check if re-sharing is allowed
668
-		if ($share->getPermissions() & Constants::PERMISSION_SHARE) {
669
-			// the recipient of the initial share is now the initiator for the re-share
670
-			$share->setSharedBy($share->getSharedWith());
671
-			$share->setSharedWith($shareWith);
672
-			$result = $this->federatedShareProvider->create($share);
673
-			$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
674
-			return ['token' => $result->getToken(), 'providerId' => $result->getId()];
675
-		} else {
676
-			throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
677
-		}
678
-	}
679
-
680
-	/**
681
-	 * update permission of a re-share so that the share dialog shows the right
682
-	 * permission if the owner or the sender changes the permission
683
-	 *
684
-	 * @param string $id
685
-	 * @param array $notification
686
-	 * @return array
687
-	 * @throws AuthenticationFailedException
688
-	 * @throws BadRequestException
689
-	 */
690
-	protected function updateResharePermissions($id, array $notification) {
691
-		throw new HintException('Updating reshares not allowed');
692
-	}
693
-
694
-	/**
695
-	 * translate OCM Permissions to Nextcloud permissions
696
-	 *
697
-	 * @param array $ocmPermissions
698
-	 * @return int
699
-	 * @throws BadRequestException
700
-	 */
701
-	protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
702
-		$ncPermissions = 0;
703
-		foreach ($ocmPermissions as $permission) {
704
-			switch (strtolower($permission)) {
705
-				case 'read':
706
-					$ncPermissions += Constants::PERMISSION_READ;
707
-					break;
708
-				case 'write':
709
-					$ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
710
-					break;
711
-				case 'share':
712
-					$ncPermissions += Constants::PERMISSION_SHARE;
713
-					break;
714
-				default:
715
-					throw new BadRequestException(['permission']);
716
-			}
717
-		}
718
-
719
-		return $ncPermissions;
720
-	}
721
-
722
-	/**
723
-	 * update permissions in database
724
-	 *
725
-	 * @param IShare $share
726
-	 * @param int $permissions
727
-	 */
728
-	protected function updatePermissionsInDatabase(IShare $share, $permissions) {
729
-		$query = $this->connection->getQueryBuilder();
730
-		$query->update('share')
731
-			->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
732
-			->set('permissions', $query->createNamedParameter($permissions))
733
-			->execute();
734
-	}
735
-
736
-
737
-	/**
738
-	 * get file
739
-	 *
740
-	 * @param string $user
741
-	 * @param int $fileSource
742
-	 * @return array with internal path of the file and a absolute link to it
743
-	 */
744
-	private function getFile($user, $fileSource) {
745
-		\OC_Util::setupFS($user);
746
-
747
-		try {
748
-			$file = Filesystem::getPath($fileSource);
749
-		} catch (NotFoundException $e) {
750
-			$file = null;
751
-		}
752
-		$args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file];
753
-		$link = Util::linkToAbsolute('files', 'index.php', $args);
754
-
755
-		return [$file, $link];
756
-	}
757
-
758
-	/**
759
-	 * check if we are the initiator or the owner of a re-share and return the correct UID
760
-	 *
761
-	 * @param IShare $share
762
-	 * @return string
763
-	 */
764
-	protected function getCorrectUid(IShare $share) {
765
-		if ($this->userManager->userExists($share->getShareOwner())) {
766
-			return $share->getShareOwner();
767
-		}
768
-
769
-		return $share->getSharedBy();
770
-	}
771
-
772
-
773
-
774
-	/**
775
-	 * check if we got the right share
776
-	 *
777
-	 * @param IShare $share
778
-	 * @param string $token
779
-	 * @return bool
780
-	 * @throws AuthenticationFailedException
781
-	 */
782
-	protected function verifyShare(IShare $share, $token) {
783
-		if (
784
-			$share->getShareType() === IShare::TYPE_REMOTE &&
785
-			$share->getToken() === $token
786
-		) {
787
-			return true;
788
-		}
789
-
790
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
791
-			try {
792
-				$knownShare = $this->shareManager->getShareByToken($token);
793
-				if ($knownShare->getId() === $share->getId()) {
794
-					return true;
795
-				}
796
-			} catch (ShareNotFound $e) {
797
-			}
798
-		}
799
-
800
-		throw new AuthenticationFailedException();
801
-	}
802
-
803
-
804
-
805
-	/**
806
-	 * check if server-to-server sharing is enabled
807
-	 *
808
-	 * @param bool $incoming
809
-	 * @return bool
810
-	 */
811
-	private function isS2SEnabled($incoming = false) {
812
-		$result = $this->appManager->isEnabledForUser('files_sharing');
813
-
814
-		if ($incoming) {
815
-			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
816
-		} else {
817
-			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
818
-		}
819
-
820
-		return $result;
821
-	}
822
-
823
-
824
-	/**
825
-	 * get the supported share types, e.g. "user", "group", etc.
826
-	 *
827
-	 * @return array
828
-	 *
829
-	 * @since 14.0.0
830
-	 */
831
-	public function getSupportedShareTypes() {
832
-		return ['user', 'group'];
833
-	}
65
+    /** @var IAppManager */
66
+    private $appManager;
67
+
68
+    /** @var FederatedShareProvider */
69
+    private $federatedShareProvider;
70
+
71
+    /** @var AddressHandler */
72
+    private $addressHandler;
73
+
74
+    /** @var ILogger */
75
+    private $logger;
76
+
77
+    /** @var IUserManager */
78
+    private $userManager;
79
+
80
+    /** @var IManager */
81
+    private $shareManager;
82
+
83
+    /** @var ICloudIdManager */
84
+    private $cloudIdManager;
85
+
86
+    /** @var IActivityManager */
87
+    private $activityManager;
88
+
89
+    /** @var INotificationManager */
90
+    private $notificationManager;
91
+
92
+    /** @var IURLGenerator */
93
+    private $urlGenerator;
94
+
95
+    /** @var ICloudFederationFactory */
96
+    private $cloudFederationFactory;
97
+
98
+    /** @var ICloudFederationProviderManager */
99
+    private $cloudFederationProviderManager;
100
+
101
+    /** @var IDBConnection */
102
+    private $connection;
103
+
104
+    /** @var IGroupManager */
105
+    private $groupManager;
106
+
107
+    /** @var IConfig */
108
+    private $config;
109
+
110
+    /**
111
+     * CloudFederationProvider constructor.
112
+     *
113
+     * @param IAppManager $appManager
114
+     * @param FederatedShareProvider $federatedShareProvider
115
+     * @param AddressHandler $addressHandler
116
+     * @param ILogger $logger
117
+     * @param IUserManager $userManager
118
+     * @param IManager $shareManager
119
+     * @param ICloudIdManager $cloudIdManager
120
+     * @param IActivityManager $activityManager
121
+     * @param INotificationManager $notificationManager
122
+     * @param IURLGenerator $urlGenerator
123
+     * @param ICloudFederationFactory $cloudFederationFactory
124
+     * @param ICloudFederationProviderManager $cloudFederationProviderManager
125
+     * @param IDBConnection $connection
126
+     * @param IGroupManager $groupManager
127
+     */
128
+    public function __construct(IAppManager $appManager,
129
+                                FederatedShareProvider $federatedShareProvider,
130
+                                AddressHandler $addressHandler,
131
+                                ILogger $logger,
132
+                                IUserManager $userManager,
133
+                                IManager $shareManager,
134
+                                ICloudIdManager $cloudIdManager,
135
+                                IActivityManager $activityManager,
136
+                                INotificationManager $notificationManager,
137
+                                IURLGenerator $urlGenerator,
138
+                                ICloudFederationFactory $cloudFederationFactory,
139
+                                ICloudFederationProviderManager $cloudFederationProviderManager,
140
+                                IDBConnection $connection,
141
+                                IGroupManager $groupManager,
142
+                                IConfig $config
143
+    ) {
144
+        $this->appManager = $appManager;
145
+        $this->federatedShareProvider = $federatedShareProvider;
146
+        $this->addressHandler = $addressHandler;
147
+        $this->logger = $logger;
148
+        $this->userManager = $userManager;
149
+        $this->shareManager = $shareManager;
150
+        $this->cloudIdManager = $cloudIdManager;
151
+        $this->activityManager = $activityManager;
152
+        $this->notificationManager = $notificationManager;
153
+        $this->urlGenerator = $urlGenerator;
154
+        $this->cloudFederationFactory = $cloudFederationFactory;
155
+        $this->cloudFederationProviderManager = $cloudFederationProviderManager;
156
+        $this->connection = $connection;
157
+        $this->groupManager = $groupManager;
158
+        $this->config = $config;
159
+    }
160
+
161
+
162
+
163
+    /**
164
+     * @return string
165
+     */
166
+    public function getShareType() {
167
+        return 'file';
168
+    }
169
+
170
+    /**
171
+     * share received from another server
172
+     *
173
+     * @param ICloudFederationShare $share
174
+     * @return string provider specific unique ID of the share
175
+     *
176
+     * @throws ProviderCouldNotAddShareException
177
+     * @throws \OCP\AppFramework\QueryException
178
+     * @throws HintException
179
+     * @since 14.0.0
180
+     */
181
+    public function shareReceived(ICloudFederationShare $share) {
182
+        if (!$this->isS2SEnabled(true)) {
183
+            throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
184
+        }
185
+
186
+        $protocol = $share->getProtocol();
187
+        if ($protocol['name'] !== 'webdav') {
188
+            throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
189
+        }
190
+
191
+        [$ownerUid, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
192
+        // for backward compatibility make sure that the remote url stored in the
193
+        // database ends with a trailing slash
194
+        if (substr($remote, -1) !== '/') {
195
+            $remote = $remote . '/';
196
+        }
197
+
198
+        $token = $share->getShareSecret();
199
+        $name = $share->getResourceName();
200
+        $owner = $share->getOwnerDisplayName();
201
+        $sharedBy = $share->getSharedByDisplayName();
202
+        $shareWith = $share->getShareWith();
203
+        $remoteId = $share->getProviderId();
204
+        $sharedByFederatedId = $share->getSharedBy();
205
+        $ownerFederatedId = $share->getOwner();
206
+        $shareType = $this->mapShareTypeToNextcloud($share->getShareType());
207
+
208
+        // if no explicit information about the person who created the share was send
209
+        // we assume that the share comes from the owner
210
+        if ($sharedByFederatedId === null) {
211
+            $sharedBy = $owner;
212
+            $sharedByFederatedId = $ownerFederatedId;
213
+        }
214
+
215
+        if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
216
+            if (!Util::isValidFileName($name)) {
217
+                throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
218
+            }
219
+
220
+            // FIXME this should be a method in the user management instead
221
+            if ($shareType === IShare::TYPE_USER) {
222
+                $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
223
+                Util::emitHook(
224
+                    '\OCA\Files_Sharing\API\Server2Server',
225
+                    'preLoginNameUsedAsUserName',
226
+                    ['uid' => &$shareWith]
227
+                );
228
+                $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
229
+
230
+                if (!$this->userManager->userExists($shareWith)) {
231
+                    throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST);
232
+                }
233
+
234
+                \OC_Util::setupFS($shareWith);
235
+            }
236
+
237
+            if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
238
+                throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST);
239
+            }
240
+
241
+            $externalManager = new \OCA\Files_Sharing\External\Manager(
242
+                \OC::$server->getDatabaseConnection(),
243
+                Filesystem::getMountManager(),
244
+                Filesystem::getLoader(),
245
+                \OC::$server->getHTTPClientService(),
246
+                \OC::$server->getNotificationManager(),
247
+                \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
248
+                \OC::$server->getCloudFederationProviderManager(),
249
+                \OC::$server->getCloudFederationFactory(),
250
+                \OC::$server->getGroupManager(),
251
+                \OC::$server->getUserManager(),
252
+                $shareWith,
253
+                \OC::$server->query(IEventDispatcher::class)
254
+            );
255
+
256
+            try {
257
+                $externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId);
258
+                $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
259
+
260
+                if ($shareType === IShare::TYPE_USER) {
261
+                    $event = $this->activityManager->generateEvent();
262
+                    $event->setApp('files_sharing')
263
+                        ->setType('remote_share')
264
+                        ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
265
+                        ->setAffectedUser($shareWith)
266
+                        ->setObject('remote_share', $shareId, $name);
267
+                    \OC::$server->getActivityManager()->publish($event);
268
+                    $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
269
+                } else {
270
+                    $groupMembers = $this->groupManager->get($shareWith)->getUsers();
271
+                    foreach ($groupMembers as $user) {
272
+                        $event = $this->activityManager->generateEvent();
273
+                        $event->setApp('files_sharing')
274
+                            ->setType('remote_share')
275
+                            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
276
+                            ->setAffectedUser($user->getUID())
277
+                            ->setObject('remote_share', $shareId, $name);
278
+                        \OC::$server->getActivityManager()->publish($event);
279
+                        $this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
280
+                    }
281
+                }
282
+                return $shareId;
283
+            } catch (\Exception $e) {
284
+                $this->logger->logException($e, [
285
+                    'message' => 'Server can not add remote share.',
286
+                    'level' => ILogger::ERROR,
287
+                    'app' => 'files_sharing'
288
+                ]);
289
+                throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
290
+            }
291
+        }
292
+
293
+        throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
294
+    }
295
+
296
+    /**
297
+     * notification received from another server
298
+     *
299
+     * @param string $notificationType (e.g. SHARE_ACCEPTED)
300
+     * @param string $providerId id of the share
301
+     * @param array $notification payload of the notification
302
+     * @return array data send back to the sender
303
+     *
304
+     * @throws ActionNotSupportedException
305
+     * @throws AuthenticationFailedException
306
+     * @throws BadRequestException
307
+     * @throws HintException
308
+     * @since 14.0.0
309
+     */
310
+    public function notificationReceived($notificationType, $providerId, array $notification) {
311
+        switch ($notificationType) {
312
+            case 'SHARE_ACCEPTED':
313
+                return $this->shareAccepted($providerId, $notification);
314
+            case 'SHARE_DECLINED':
315
+                return $this->shareDeclined($providerId, $notification);
316
+            case 'SHARE_UNSHARED':
317
+                return $this->unshare($providerId, $notification);
318
+            case 'REQUEST_RESHARE':
319
+                return $this->reshareRequested($providerId, $notification);
320
+            case 'RESHARE_UNDO':
321
+                return $this->undoReshare($providerId, $notification);
322
+            case 'RESHARE_CHANGE_PERMISSION':
323
+                return $this->updateResharePermissions($providerId, $notification);
324
+        }
325
+
326
+
327
+        throw new BadRequestException([$notificationType]);
328
+    }
329
+
330
+    /**
331
+     * map OCM share type (strings) to Nextcloud internal share types (integer)
332
+     *
333
+     * @param string $shareType
334
+     * @return int
335
+     */
336
+    private function mapShareTypeToNextcloud($shareType) {
337
+        $result = IShare::TYPE_USER;
338
+        if ($shareType === 'group') {
339
+            $result = IShare::TYPE_GROUP;
340
+        }
341
+
342
+        return $result;
343
+    }
344
+
345
+    private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name): void {
346
+        $notification = $this->notificationManager->createNotification();
347
+        $notification->setApp('files_sharing')
348
+            ->setUser($shareWith)
349
+            ->setDateTime(new \DateTime())
350
+            ->setObject('remote_share', $shareId)
351
+            ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
352
+
353
+        $declineAction = $notification->createAction();
354
+        $declineAction->setLabel('decline')
355
+            ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
356
+        $notification->addAction($declineAction);
357
+
358
+        $acceptAction = $notification->createAction();
359
+        $acceptAction->setLabel('accept')
360
+            ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
361
+        $notification->addAction($acceptAction);
362
+
363
+        $this->notificationManager->notify($notification);
364
+    }
365
+
366
+    /**
367
+     * process notification that the recipient accepted a share
368
+     *
369
+     * @param string $id
370
+     * @param array $notification
371
+     * @return array
372
+     * @throws ActionNotSupportedException
373
+     * @throws AuthenticationFailedException
374
+     * @throws BadRequestException
375
+     * @throws HintException
376
+     */
377
+    private function shareAccepted($id, array $notification) {
378
+        if (!$this->isS2SEnabled()) {
379
+            throw new ActionNotSupportedException('Server does not support federated cloud sharing');
380
+        }
381
+
382
+        if (!isset($notification['sharedSecret'])) {
383
+            throw new BadRequestException(['sharedSecret']);
384
+        }
385
+
386
+        $token = $notification['sharedSecret'];
387
+
388
+        $share = $this->federatedShareProvider->getShareById($id);
389
+
390
+        $this->verifyShare($share, $token);
391
+        $this->executeAcceptShare($share);
392
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
393
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
394
+            $remoteId = $this->federatedShareProvider->getRemoteId($share);
395
+            $notification = $this->cloudFederationFactory->getCloudFederationNotification();
396
+            $notification->setMessage(
397
+                'SHARE_ACCEPTED',
398
+                'file',
399
+                $remoteId,
400
+                [
401
+                    'sharedSecret' => $token,
402
+                    'message' => 'Recipient accepted the re-share'
403
+                ]
404
+
405
+            );
406
+            $this->cloudFederationProviderManager->sendNotification($remote, $notification);
407
+        }
408
+
409
+        return [];
410
+    }
411
+
412
+    /**
413
+     * @param IShare $share
414
+     * @throws ShareNotFound
415
+     */
416
+    protected function executeAcceptShare(IShare $share) {
417
+        try {
418
+            $fileId = (int)$share->getNode()->getId();
419
+            [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
420
+        } catch (\Exception $e) {
421
+            throw new ShareNotFound();
422
+        }
423
+
424
+        $event = $this->activityManager->generateEvent();
425
+        $event->setApp('files_sharing')
426
+            ->setType('remote_share')
427
+            ->setAffectedUser($this->getCorrectUid($share))
428
+            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
429
+            ->setObject('files', $fileId, $file)
430
+            ->setLink($link);
431
+        $this->activityManager->publish($event);
432
+    }
433
+
434
+    /**
435
+     * process notification that the recipient declined a share
436
+     *
437
+     * @param string $id
438
+     * @param array $notification
439
+     * @return array
440
+     * @throws ActionNotSupportedException
441
+     * @throws AuthenticationFailedException
442
+     * @throws BadRequestException
443
+     * @throws ShareNotFound
444
+     * @throws HintException
445
+     *
446
+     */
447
+    protected function shareDeclined($id, array $notification) {
448
+        if (!$this->isS2SEnabled()) {
449
+            throw new ActionNotSupportedException('Server does not support federated cloud sharing');
450
+        }
451
+
452
+        if (!isset($notification['sharedSecret'])) {
453
+            throw new BadRequestException(['sharedSecret']);
454
+        }
455
+
456
+        $token = $notification['sharedSecret'];
457
+
458
+        $share = $this->federatedShareProvider->getShareById($id);
459
+
460
+        $this->verifyShare($share, $token);
461
+
462
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
463
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
464
+            $remoteId = $this->federatedShareProvider->getRemoteId($share);
465
+            $notification = $this->cloudFederationFactory->getCloudFederationNotification();
466
+            $notification->setMessage(
467
+                'SHARE_DECLINED',
468
+                'file',
469
+                $remoteId,
470
+                [
471
+                    'sharedSecret' => $token,
472
+                    'message' => 'Recipient declined the re-share'
473
+                ]
474
+
475
+            );
476
+            $this->cloudFederationProviderManager->sendNotification($remote, $notification);
477
+        }
478
+
479
+        $this->executeDeclineShare($share);
480
+
481
+        return [];
482
+    }
483
+
484
+    /**
485
+     * delete declined share and create a activity
486
+     *
487
+     * @param IShare $share
488
+     * @throws ShareNotFound
489
+     */
490
+    protected function executeDeclineShare(IShare $share) {
491
+        $this->federatedShareProvider->removeShareFromTable($share);
492
+
493
+        try {
494
+            $fileId = (int)$share->getNode()->getId();
495
+            [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
496
+        } catch (\Exception $e) {
497
+            throw new ShareNotFound();
498
+        }
499
+
500
+        $event = $this->activityManager->generateEvent();
501
+        $event->setApp('files_sharing')
502
+            ->setType('remote_share')
503
+            ->setAffectedUser($this->getCorrectUid($share))
504
+            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
505
+            ->setObject('files', $fileId, $file)
506
+            ->setLink($link);
507
+        $this->activityManager->publish($event);
508
+    }
509
+
510
+    /**
511
+     * received the notification that the owner unshared a file from you
512
+     *
513
+     * @param string $id
514
+     * @param array $notification
515
+     * @return array
516
+     * @throws AuthenticationFailedException
517
+     * @throws BadRequestException
518
+     */
519
+    private function undoReshare($id, array $notification) {
520
+        if (!isset($notification['sharedSecret'])) {
521
+            throw new BadRequestException(['sharedSecret']);
522
+        }
523
+        $token = $notification['sharedSecret'];
524
+
525
+        $share = $this->federatedShareProvider->getShareById($id);
526
+
527
+        $this->verifyShare($share, $token);
528
+        $this->federatedShareProvider->removeShareFromTable($share);
529
+        return [];
530
+    }
531
+
532
+    /**
533
+     * unshare file from self
534
+     *
535
+     * @param string $id
536
+     * @param array $notification
537
+     * @return array
538
+     * @throws ActionNotSupportedException
539
+     * @throws BadRequestException
540
+     */
541
+    private function unshare($id, array $notification) {
542
+        if (!$this->isS2SEnabled(true)) {
543
+            throw new ActionNotSupportedException("incoming shares disabled!");
544
+        }
545
+
546
+        if (!isset($notification['sharedSecret'])) {
547
+            throw new BadRequestException(['sharedSecret']);
548
+        }
549
+        $token = $notification['sharedSecret'];
550
+
551
+        $qb = $this->connection->getQueryBuilder();
552
+        $qb->select('*')
553
+            ->from('share_external')
554
+            ->where(
555
+                $qb->expr()->andX(
556
+                    $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
557
+                    $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
558
+                )
559
+            );
560
+
561
+        $result = $qb->execute();
562
+        $share = $result->fetch();
563
+        $result->closeCursor();
564
+
565
+        if ($token && $id && !empty($share)) {
566
+            $remote = $this->cleanupRemote($share['remote']);
567
+
568
+            $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
569
+            $mountpoint = $share['mountpoint'];
570
+            $user = $share['user'];
571
+
572
+            $qb = $this->connection->getQueryBuilder();
573
+            $qb->delete('share_external')
574
+                ->where(
575
+                    $qb->expr()->andX(
576
+                        $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
577
+                        $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
578
+                    )
579
+                );
580
+
581
+            $qb->execute();
582
+
583
+            // delete all child in case of a group share
584
+            $qb = $this->connection->getQueryBuilder();
585
+            $qb->delete('share_external')
586
+                ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
587
+            $qb->execute();
588
+
589
+            if ((int)$share['share_type'] === IShare::TYPE_USER) {
590
+                if ($share['accepted']) {
591
+                    $path = trim($mountpoint, '/');
592
+                } else {
593
+                    $path = trim($share['name'], '/');
594
+                }
595
+                $notification = $this->notificationManager->createNotification();
596
+                $notification->setApp('files_sharing')
597
+                    ->setUser($share['user'])
598
+                    ->setObject('remote_share', (int)$share['id']);
599
+                $this->notificationManager->markProcessed($notification);
600
+
601
+                $event = $this->activityManager->generateEvent();
602
+                $event->setApp('files_sharing')
603
+                    ->setType('remote_share')
604
+                    ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
605
+                    ->setAffectedUser($user)
606
+                    ->setObject('remote_share', (int)$share['id'], $path);
607
+                \OC::$server->getActivityManager()->publish($event);
608
+            }
609
+        }
610
+
611
+        return [];
612
+    }
613
+
614
+    private function cleanupRemote($remote) {
615
+        $remote = substr($remote, strpos($remote, '://') + 3);
616
+
617
+        return rtrim($remote, '/');
618
+    }
619
+
620
+    /**
621
+     * recipient of a share request to re-share the file with another user
622
+     *
623
+     * @param string $id
624
+     * @param array $notification
625
+     * @return array
626
+     * @throws AuthenticationFailedException
627
+     * @throws BadRequestException
628
+     * @throws ProviderCouldNotAddShareException
629
+     * @throws ShareNotFound
630
+     */
631
+    protected function reshareRequested($id, array $notification) {
632
+        if (!isset($notification['sharedSecret'])) {
633
+            throw new BadRequestException(['sharedSecret']);
634
+        }
635
+        $token = $notification['sharedSecret'];
636
+
637
+        if (!isset($notification['shareWith'])) {
638
+            throw new BadRequestException(['shareWith']);
639
+        }
640
+        $shareWith = $notification['shareWith'];
641
+
642
+        if (!isset($notification['senderId'])) {
643
+            throw new BadRequestException(['senderId']);
644
+        }
645
+        $senderId = $notification['senderId'];
646
+
647
+        $share = $this->federatedShareProvider->getShareById($id);
648
+
649
+        // We have to respect the default share permissions
650
+        $permissions = $share->getPermissions() & (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
651
+        $share->setPermissions($permissions);
652
+
653
+        // don't allow to share a file back to the owner
654
+        try {
655
+            [$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
656
+            $owner = $share->getShareOwner();
657
+            $currentServer = $this->addressHandler->generateRemoteURL();
658
+            if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
659
+                throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
660
+            }
661
+        } catch (\Exception $e) {
662
+            throw new ProviderCouldNotAddShareException($e->getMessage());
663
+        }
664
+
665
+        $this->verifyShare($share, $token);
666
+
667
+        // check if re-sharing is allowed
668
+        if ($share->getPermissions() & Constants::PERMISSION_SHARE) {
669
+            // the recipient of the initial share is now the initiator for the re-share
670
+            $share->setSharedBy($share->getSharedWith());
671
+            $share->setSharedWith($shareWith);
672
+            $result = $this->federatedShareProvider->create($share);
673
+            $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
674
+            return ['token' => $result->getToken(), 'providerId' => $result->getId()];
675
+        } else {
676
+            throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
677
+        }
678
+    }
679
+
680
+    /**
681
+     * update permission of a re-share so that the share dialog shows the right
682
+     * permission if the owner or the sender changes the permission
683
+     *
684
+     * @param string $id
685
+     * @param array $notification
686
+     * @return array
687
+     * @throws AuthenticationFailedException
688
+     * @throws BadRequestException
689
+     */
690
+    protected function updateResharePermissions($id, array $notification) {
691
+        throw new HintException('Updating reshares not allowed');
692
+    }
693
+
694
+    /**
695
+     * translate OCM Permissions to Nextcloud permissions
696
+     *
697
+     * @param array $ocmPermissions
698
+     * @return int
699
+     * @throws BadRequestException
700
+     */
701
+    protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
702
+        $ncPermissions = 0;
703
+        foreach ($ocmPermissions as $permission) {
704
+            switch (strtolower($permission)) {
705
+                case 'read':
706
+                    $ncPermissions += Constants::PERMISSION_READ;
707
+                    break;
708
+                case 'write':
709
+                    $ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
710
+                    break;
711
+                case 'share':
712
+                    $ncPermissions += Constants::PERMISSION_SHARE;
713
+                    break;
714
+                default:
715
+                    throw new BadRequestException(['permission']);
716
+            }
717
+        }
718
+
719
+        return $ncPermissions;
720
+    }
721
+
722
+    /**
723
+     * update permissions in database
724
+     *
725
+     * @param IShare $share
726
+     * @param int $permissions
727
+     */
728
+    protected function updatePermissionsInDatabase(IShare $share, $permissions) {
729
+        $query = $this->connection->getQueryBuilder();
730
+        $query->update('share')
731
+            ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
732
+            ->set('permissions', $query->createNamedParameter($permissions))
733
+            ->execute();
734
+    }
735
+
736
+
737
+    /**
738
+     * get file
739
+     *
740
+     * @param string $user
741
+     * @param int $fileSource
742
+     * @return array with internal path of the file and a absolute link to it
743
+     */
744
+    private function getFile($user, $fileSource) {
745
+        \OC_Util::setupFS($user);
746
+
747
+        try {
748
+            $file = Filesystem::getPath($fileSource);
749
+        } catch (NotFoundException $e) {
750
+            $file = null;
751
+        }
752
+        $args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file];
753
+        $link = Util::linkToAbsolute('files', 'index.php', $args);
754
+
755
+        return [$file, $link];
756
+    }
757
+
758
+    /**
759
+     * check if we are the initiator or the owner of a re-share and return the correct UID
760
+     *
761
+     * @param IShare $share
762
+     * @return string
763
+     */
764
+    protected function getCorrectUid(IShare $share) {
765
+        if ($this->userManager->userExists($share->getShareOwner())) {
766
+            return $share->getShareOwner();
767
+        }
768
+
769
+        return $share->getSharedBy();
770
+    }
771
+
772
+
773
+
774
+    /**
775
+     * check if we got the right share
776
+     *
777
+     * @param IShare $share
778
+     * @param string $token
779
+     * @return bool
780
+     * @throws AuthenticationFailedException
781
+     */
782
+    protected function verifyShare(IShare $share, $token) {
783
+        if (
784
+            $share->getShareType() === IShare::TYPE_REMOTE &&
785
+            $share->getToken() === $token
786
+        ) {
787
+            return true;
788
+        }
789
+
790
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
791
+            try {
792
+                $knownShare = $this->shareManager->getShareByToken($token);
793
+                if ($knownShare->getId() === $share->getId()) {
794
+                    return true;
795
+                }
796
+            } catch (ShareNotFound $e) {
797
+            }
798
+        }
799
+
800
+        throw new AuthenticationFailedException();
801
+    }
802
+
803
+
804
+
805
+    /**
806
+     * check if server-to-server sharing is enabled
807
+     *
808
+     * @param bool $incoming
809
+     * @return bool
810
+     */
811
+    private function isS2SEnabled($incoming = false) {
812
+        $result = $this->appManager->isEnabledForUser('files_sharing');
813
+
814
+        if ($incoming) {
815
+            $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
816
+        } else {
817
+            $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
818
+        }
819
+
820
+        return $result;
821
+    }
822
+
823
+
824
+    /**
825
+     * get the supported share types, e.g. "user", "group", etc.
826
+     *
827
+     * @return array
828
+     *
829
+     * @since 14.0.0
830
+     */
831
+    public function getSupportedShareTypes() {
832
+        return ['user', 'group'];
833
+    }
834 834
 }
Please login to merge, or discard this patch.