Passed
Push — master ( 77a436...c4fddd )
by Lukas
17:57 queued 12s
created
apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php 2 patches
Indentation   +769 added lines, -769 removed lines patch added patch discarded remove patch
@@ -64,773 +64,773 @@
 block discarded – undo
64 64
 
65 65
 class CloudFederationProviderFiles implements ICloudFederationProvider {
66 66
 
67
-	/** @var IAppManager */
68
-	private $appManager;
69
-
70
-	/** @var FederatedShareProvider */
71
-	private $federatedShareProvider;
72
-
73
-	/** @var AddressHandler */
74
-	private $addressHandler;
75
-
76
-	/** @var ILogger */
77
-	private $logger;
78
-
79
-	/** @var IUserManager */
80
-	private $userManager;
81
-
82
-	/** @var IManager */
83
-	private $shareManager;
84
-
85
-	/** @var ICloudIdManager */
86
-	private $cloudIdManager;
87
-
88
-	/** @var IActivityManager */
89
-	private $activityManager;
90
-
91
-	/** @var INotificationManager */
92
-	private $notificationManager;
93
-
94
-	/** @var IURLGenerator */
95
-	private $urlGenerator;
96
-
97
-	/** @var ICloudFederationFactory */
98
-	private $cloudFederationFactory;
99
-
100
-	/** @var ICloudFederationProviderManager */
101
-	private $cloudFederationProviderManager;
102
-
103
-	/** @var IDBConnection */
104
-	private $connection;
105
-
106
-	/** @var IGroupManager */
107
-	private $groupManager;
108
-
109
-	/** @var IConfig */
110
-	private $config;
111
-
112
-	/**
113
-	 * CloudFederationProvider constructor.
114
-	 *
115
-	 * @param IAppManager $appManager
116
-	 * @param FederatedShareProvider $federatedShareProvider
117
-	 * @param AddressHandler $addressHandler
118
-	 * @param ILogger $logger
119
-	 * @param IUserManager $userManager
120
-	 * @param IManager $shareManager
121
-	 * @param ICloudIdManager $cloudIdManager
122
-	 * @param IActivityManager $activityManager
123
-	 * @param INotificationManager $notificationManager
124
-	 * @param IURLGenerator $urlGenerator
125
-	 * @param ICloudFederationFactory $cloudFederationFactory
126
-	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
127
-	 * @param IDBConnection $connection
128
-	 * @param IGroupManager $groupManager
129
-	 */
130
-	public function __construct(IAppManager $appManager,
131
-								FederatedShareProvider $federatedShareProvider,
132
-								AddressHandler $addressHandler,
133
-								ILogger $logger,
134
-								IUserManager $userManager,
135
-								IManager $shareManager,
136
-								ICloudIdManager $cloudIdManager,
137
-								IActivityManager $activityManager,
138
-								INotificationManager $notificationManager,
139
-								IURLGenerator $urlGenerator,
140
-								ICloudFederationFactory $cloudFederationFactory,
141
-								ICloudFederationProviderManager $cloudFederationProviderManager,
142
-								IDBConnection $connection,
143
-								IGroupManager $groupManager,
144
-								IConfig $config
145
-	) {
146
-		$this->appManager = $appManager;
147
-		$this->federatedShareProvider = $federatedShareProvider;
148
-		$this->addressHandler = $addressHandler;
149
-		$this->logger = $logger;
150
-		$this->userManager = $userManager;
151
-		$this->shareManager = $shareManager;
152
-		$this->cloudIdManager = $cloudIdManager;
153
-		$this->activityManager = $activityManager;
154
-		$this->notificationManager = $notificationManager;
155
-		$this->urlGenerator = $urlGenerator;
156
-		$this->cloudFederationFactory = $cloudFederationFactory;
157
-		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
158
-		$this->connection = $connection;
159
-		$this->groupManager = $groupManager;
160
-		$this->config = $config;
161
-	}
162
-
163
-
164
-
165
-	/**
166
-	 * @return string
167
-	 */
168
-	public function getShareType() {
169
-		return 'file';
170
-	}
171
-
172
-	/**
173
-	 * share received from another server
174
-	 *
175
-	 * @param ICloudFederationShare $share
176
-	 * @return string provider specific unique ID of the share
177
-	 *
178
-	 * @throws ProviderCouldNotAddShareException
179
-	 * @throws \OCP\AppFramework\QueryException
180
-	 * @throws \OC\HintException
181
-	 * @since 14.0.0
182
-	 */
183
-	public function shareReceived(ICloudFederationShare $share) {
184
-		if (!$this->isS2SEnabled(true)) {
185
-			throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
186
-		}
187
-
188
-		$protocol = $share->getProtocol();
189
-		if ($protocol['name'] !== 'webdav') {
190
-			throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
191
-		}
192
-
193
-		[$ownerUid, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
194
-		// for backward compatibility make sure that the remote url stored in the
195
-		// database ends with a trailing slash
196
-		if (substr($remote, -1) !== '/') {
197
-			$remote = $remote . '/';
198
-		}
199
-
200
-		$token = $share->getShareSecret();
201
-		$name = $share->getResourceName();
202
-		$owner = $share->getOwnerDisplayName();
203
-		$sharedBy = $share->getSharedByDisplayName();
204
-		$shareWith = $share->getShareWith();
205
-		$remoteId = $share->getProviderId();
206
-		$sharedByFederatedId = $share->getSharedBy();
207
-		$ownerFederatedId = $share->getOwner();
208
-		$shareType = $this->mapShareTypeToNextcloud($share->getShareType());
209
-
210
-		// if no explicit information about the person who created the share was send
211
-		// we assume that the share comes from the owner
212
-		if ($sharedByFederatedId === null) {
213
-			$sharedBy = $owner;
214
-			$sharedByFederatedId = $ownerFederatedId;
215
-		}
216
-
217
-		if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
218
-			if (!Util::isValidFileName($name)) {
219
-				throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
220
-			}
221
-
222
-			// FIXME this should be a method in the user management instead
223
-			if ($shareType === IShare::TYPE_USER) {
224
-				$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
225
-				Util::emitHook(
226
-					'\OCA\Files_Sharing\API\Server2Server',
227
-					'preLoginNameUsedAsUserName',
228
-					['uid' => &$shareWith]
229
-				);
230
-				$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
231
-
232
-				if (!$this->userManager->userExists($shareWith)) {
233
-					throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST);
234
-				}
235
-
236
-				\OC_Util::setupFS($shareWith);
237
-			}
238
-
239
-			if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
240
-				throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST);
241
-			}
242
-
243
-			$externalManager = new \OCA\Files_Sharing\External\Manager(
244
-				\OC::$server->getDatabaseConnection(),
245
-				Filesystem::getMountManager(),
246
-				Filesystem::getLoader(),
247
-				\OC::$server->getHTTPClientService(),
248
-				\OC::$server->getNotificationManager(),
249
-				\OC::$server->query(\OCP\OCS\IDiscoveryService::class),
250
-				\OC::$server->getCloudFederationProviderManager(),
251
-				\OC::$server->getCloudFederationFactory(),
252
-				\OC::$server->getGroupManager(),
253
-				\OC::$server->getUserManager(),
254
-				$shareWith,
255
-				\OC::$server->query(IEventDispatcher::class)
256
-			);
257
-
258
-			try {
259
-				$externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId);
260
-				$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
261
-
262
-				if ($shareType === IShare::TYPE_USER) {
263
-					$event = $this->activityManager->generateEvent();
264
-					$event->setApp('files_sharing')
265
-						->setType('remote_share')
266
-						->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
267
-						->setAffectedUser($shareWith)
268
-						->setObject('remote_share', $shareId, $name);
269
-					\OC::$server->getActivityManager()->publish($event);
270
-					$this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
271
-				} else {
272
-					$groupMembers = $this->groupManager->get($shareWith)->getUsers();
273
-					foreach ($groupMembers as $user) {
274
-						$event = $this->activityManager->generateEvent();
275
-						$event->setApp('files_sharing')
276
-							->setType('remote_share')
277
-							->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
278
-							->setAffectedUser($user->getUID())
279
-							->setObject('remote_share', $shareId, $name);
280
-						\OC::$server->getActivityManager()->publish($event);
281
-						$this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
282
-					}
283
-				}
284
-				return $shareId;
285
-			} catch (\Exception $e) {
286
-				$this->logger->logException($e, [
287
-					'message' => 'Server can not add remote share.',
288
-					'level' => ILogger::ERROR,
289
-					'app' => 'files_sharing'
290
-				]);
291
-				throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
292
-			}
293
-		}
294
-
295
-		throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
296
-	}
297
-
298
-	/**
299
-	 * notification received from another server
300
-	 *
301
-	 * @param string $notificationType (e.g. SHARE_ACCEPTED)
302
-	 * @param string $providerId id of the share
303
-	 * @param array $notification payload of the notification
304
-	 * @return array data send back to the sender
305
-	 *
306
-	 * @throws ActionNotSupportedException
307
-	 * @throws AuthenticationFailedException
308
-	 * @throws BadRequestException
309
-	 * @throws \OC\HintException
310
-	 * @since 14.0.0
311
-	 */
312
-	public function notificationReceived($notificationType, $providerId, array $notification) {
313
-		switch ($notificationType) {
314
-			case 'SHARE_ACCEPTED':
315
-				return $this->shareAccepted($providerId, $notification);
316
-			case 'SHARE_DECLINED':
317
-				return $this->shareDeclined($providerId, $notification);
318
-			case 'SHARE_UNSHARED':
319
-				return $this->unshare($providerId, $notification);
320
-			case 'REQUEST_RESHARE':
321
-				return $this->reshareRequested($providerId, $notification);
322
-			case 'RESHARE_UNDO':
323
-				return $this->undoReshare($providerId, $notification);
324
-			case 'RESHARE_CHANGE_PERMISSION':
325
-				return $this->updateResharePermissions($providerId, $notification);
326
-		}
327
-
328
-
329
-		throw new BadRequestException([$notificationType]);
330
-	}
331
-
332
-	/**
333
-	 * map OCM share type (strings) to Nextcloud internal share types (integer)
334
-	 *
335
-	 * @param string $shareType
336
-	 * @return int
337
-	 */
338
-	private function mapShareTypeToNextcloud($shareType) {
339
-		$result = IShare::TYPE_USER;
340
-		if ($shareType === 'group') {
341
-			$result = IShare::TYPE_GROUP;
342
-		}
343
-
344
-		return $result;
345
-	}
346
-
347
-	private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name): void {
348
-		$notification = $this->notificationManager->createNotification();
349
-		$notification->setApp('files_sharing')
350
-			->setUser($shareWith)
351
-			->setDateTime(new \DateTime())
352
-			->setObject('remote_share', $shareId)
353
-			->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
354
-
355
-		$declineAction = $notification->createAction();
356
-		$declineAction->setLabel('decline')
357
-			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
358
-		$notification->addAction($declineAction);
359
-
360
-		$acceptAction = $notification->createAction();
361
-		$acceptAction->setLabel('accept')
362
-			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
363
-		$notification->addAction($acceptAction);
364
-
365
-		$this->notificationManager->notify($notification);
366
-	}
367
-
368
-	/**
369
-	 * process notification that the recipient accepted a share
370
-	 *
371
-	 * @param string $id
372
-	 * @param array $notification
373
-	 * @return array
374
-	 * @throws ActionNotSupportedException
375
-	 * @throws AuthenticationFailedException
376
-	 * @throws BadRequestException
377
-	 * @throws \OC\HintException
378
-	 */
379
-	private function shareAccepted($id, array $notification) {
380
-		if (!$this->isS2SEnabled()) {
381
-			throw new ActionNotSupportedException('Server does not support federated cloud sharing');
382
-		}
383
-
384
-		if (!isset($notification['sharedSecret'])) {
385
-			throw new BadRequestException(['sharedSecret']);
386
-		}
387
-
388
-		$token = $notification['sharedSecret'];
389
-
390
-		$share = $this->federatedShareProvider->getShareById($id);
391
-
392
-		$this->verifyShare($share, $token);
393
-		$this->executeAcceptShare($share);
394
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
395
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
396
-			$remoteId = $this->federatedShareProvider->getRemoteId($share);
397
-			$notification = $this->cloudFederationFactory->getCloudFederationNotification();
398
-			$notification->setMessage(
399
-				'SHARE_ACCEPTED',
400
-				'file',
401
-				$remoteId,
402
-				[
403
-					'sharedSecret' => $token,
404
-					'message' => 'Recipient accepted the re-share'
405
-				]
406
-
407
-			);
408
-			$this->cloudFederationProviderManager->sendNotification($remote, $notification);
409
-		}
410
-
411
-		return [];
412
-	}
413
-
414
-	/**
415
-	 * @param IShare $share
416
-	 * @throws ShareNotFound
417
-	 */
418
-	protected function executeAcceptShare(IShare $share) {
419
-		try {
420
-			$fileId = (int)$share->getNode()->getId();
421
-			[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
422
-		} catch (\Exception $e) {
423
-			throw new ShareNotFound();
424
-		}
425
-
426
-		$event = $this->activityManager->generateEvent();
427
-		$event->setApp('files_sharing')
428
-			->setType('remote_share')
429
-			->setAffectedUser($this->getCorrectUid($share))
430
-			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
431
-			->setObject('files', $fileId, $file)
432
-			->setLink($link);
433
-		$this->activityManager->publish($event);
434
-	}
435
-
436
-	/**
437
-	 * process notification that the recipient declined a share
438
-	 *
439
-	 * @param string $id
440
-	 * @param array $notification
441
-	 * @return array
442
-	 * @throws ActionNotSupportedException
443
-	 * @throws AuthenticationFailedException
444
-	 * @throws BadRequestException
445
-	 * @throws ShareNotFound
446
-	 * @throws \OC\HintException
447
-	 *
448
-	 */
449
-	protected function shareDeclined($id, array $notification) {
450
-		if (!$this->isS2SEnabled()) {
451
-			throw new ActionNotSupportedException('Server does not support federated cloud sharing');
452
-		}
453
-
454
-		if (!isset($notification['sharedSecret'])) {
455
-			throw new BadRequestException(['sharedSecret']);
456
-		}
457
-
458
-		$token = $notification['sharedSecret'];
459
-
460
-		$share = $this->federatedShareProvider->getShareById($id);
461
-
462
-		$this->verifyShare($share, $token);
463
-
464
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
465
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
466
-			$remoteId = $this->federatedShareProvider->getRemoteId($share);
467
-			$notification = $this->cloudFederationFactory->getCloudFederationNotification();
468
-			$notification->setMessage(
469
-				'SHARE_DECLINED',
470
-				'file',
471
-				$remoteId,
472
-				[
473
-					'sharedSecret' => $token,
474
-					'message' => 'Recipient declined the re-share'
475
-				]
476
-
477
-			);
478
-			$this->cloudFederationProviderManager->sendNotification($remote, $notification);
479
-		}
480
-
481
-		$this->executeDeclineShare($share);
482
-
483
-		return [];
484
-	}
485
-
486
-	/**
487
-	 * delete declined share and create a activity
488
-	 *
489
-	 * @param IShare $share
490
-	 * @throws ShareNotFound
491
-	 */
492
-	protected function executeDeclineShare(IShare $share) {
493
-		$this->federatedShareProvider->removeShareFromTable($share);
494
-
495
-		try {
496
-			$fileId = (int)$share->getNode()->getId();
497
-			[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
498
-		} catch (\Exception $e) {
499
-			throw new ShareNotFound();
500
-		}
501
-
502
-		$event = $this->activityManager->generateEvent();
503
-		$event->setApp('files_sharing')
504
-			->setType('remote_share')
505
-			->setAffectedUser($this->getCorrectUid($share))
506
-			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
507
-			->setObject('files', $fileId, $file)
508
-			->setLink($link);
509
-		$this->activityManager->publish($event);
510
-	}
511
-
512
-	/**
513
-	 * received the notification that the owner unshared a file from you
514
-	 *
515
-	 * @param string $id
516
-	 * @param array $notification
517
-	 * @return array
518
-	 * @throws AuthenticationFailedException
519
-	 * @throws BadRequestException
520
-	 */
521
-	private function undoReshare($id, array $notification) {
522
-		if (!isset($notification['sharedSecret'])) {
523
-			throw new BadRequestException(['sharedSecret']);
524
-		}
525
-		$token = $notification['sharedSecret'];
526
-
527
-		$share = $this->federatedShareProvider->getShareById($id);
528
-
529
-		$this->verifyShare($share, $token);
530
-		$this->federatedShareProvider->removeShareFromTable($share);
531
-		return [];
532
-	}
533
-
534
-	/**
535
-	 * unshare file from self
536
-	 *
537
-	 * @param string $id
538
-	 * @param array $notification
539
-	 * @return array
540
-	 * @throws ActionNotSupportedException
541
-	 * @throws BadRequestException
542
-	 */
543
-	private function unshare($id, array $notification) {
544
-		if (!$this->isS2SEnabled(true)) {
545
-			throw new ActionNotSupportedException("incoming shares disabled!");
546
-		}
547
-
548
-		if (!isset($notification['sharedSecret'])) {
549
-			throw new BadRequestException(['sharedSecret']);
550
-		}
551
-		$token = $notification['sharedSecret'];
552
-
553
-		$qb = $this->connection->getQueryBuilder();
554
-		$qb->select('*')
555
-			->from('share_external')
556
-			->where(
557
-				$qb->expr()->andX(
558
-					$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
559
-					$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
560
-				)
561
-			);
562
-
563
-		$result = $qb->execute();
564
-		$share = $result->fetch();
565
-		$result->closeCursor();
566
-
567
-		if ($token && $id && !empty($share)) {
568
-			$remote = $this->cleanupRemote($share['remote']);
569
-
570
-			$owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
571
-			$mountpoint = $share['mountpoint'];
572
-			$user = $share['user'];
573
-
574
-			$qb = $this->connection->getQueryBuilder();
575
-			$qb->delete('share_external')
576
-				->where(
577
-					$qb->expr()->andX(
578
-						$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
579
-						$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
580
-					)
581
-				);
582
-
583
-			$qb->execute();
584
-
585
-			// delete all child in case of a group share
586
-			$qb = $this->connection->getQueryBuilder();
587
-			$qb->delete('share_external')
588
-				->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
589
-			$qb->execute();
590
-
591
-			if ((int)$share['share_type'] === IShare::TYPE_USER) {
592
-				if ($share['accepted']) {
593
-					$path = trim($mountpoint, '/');
594
-				} else {
595
-					$path = trim($share['name'], '/');
596
-				}
597
-				$notification = $this->notificationManager->createNotification();
598
-				$notification->setApp('files_sharing')
599
-					->setUser($share['user'])
600
-					->setObject('remote_share', (int)$share['id']);
601
-				$this->notificationManager->markProcessed($notification);
602
-
603
-				$event = $this->activityManager->generateEvent();
604
-				$event->setApp('files_sharing')
605
-					->setType('remote_share')
606
-					->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
607
-					->setAffectedUser($user)
608
-					->setObject('remote_share', (int)$share['id'], $path);
609
-				\OC::$server->getActivityManager()->publish($event);
610
-			}
611
-		}
612
-
613
-		return [];
614
-	}
615
-
616
-	private function cleanupRemote($remote) {
617
-		$remote = substr($remote, strpos($remote, '://') + 3);
618
-
619
-		return rtrim($remote, '/');
620
-	}
621
-
622
-	/**
623
-	 * recipient of a share request to re-share the file with another user
624
-	 *
625
-	 * @param string $id
626
-	 * @param array $notification
627
-	 * @return array
628
-	 * @throws AuthenticationFailedException
629
-	 * @throws BadRequestException
630
-	 * @throws ProviderCouldNotAddShareException
631
-	 * @throws ShareNotFound
632
-	 */
633
-	protected function reshareRequested($id, array $notification) {
634
-		if (!isset($notification['sharedSecret'])) {
635
-			throw new BadRequestException(['sharedSecret']);
636
-		}
637
-		$token = $notification['sharedSecret'];
638
-
639
-		if (!isset($notification['shareWith'])) {
640
-			throw new BadRequestException(['shareWith']);
641
-		}
642
-		$shareWith = $notification['shareWith'];
643
-
644
-		if (!isset($notification['senderId'])) {
645
-			throw new BadRequestException(['senderId']);
646
-		}
647
-		$senderId = $notification['senderId'];
648
-
649
-		$share = $this->federatedShareProvider->getShareById($id);
650
-
651
-		// We have to respect the default share permissions
652
-		$permissions = $share->getPermissions() & (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
653
-		$share->setPermissions($permissions);
654
-
655
-		// don't allow to share a file back to the owner
656
-		try {
657
-			[$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
658
-			$owner = $share->getShareOwner();
659
-			$currentServer = $this->addressHandler->generateRemoteURL();
660
-			if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
661
-				throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
662
-			}
663
-		} catch (\Exception $e) {
664
-			throw new ProviderCouldNotAddShareException($e->getMessage());
665
-		}
666
-
667
-		$this->verifyShare($share, $token);
668
-
669
-		// check if re-sharing is allowed
670
-		if ($share->getPermissions() & Constants::PERMISSION_SHARE) {
671
-			// the recipient of the initial share is now the initiator for the re-share
672
-			$share->setSharedBy($share->getSharedWith());
673
-			$share->setSharedWith($shareWith);
674
-			$result = $this->federatedShareProvider->create($share);
675
-			$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
676
-			return ['token' => $result->getToken(), 'providerId' => $result->getId()];
677
-		} else {
678
-			throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
679
-		}
680
-	}
681
-
682
-	/**
683
-	 * update permission of a re-share so that the share dialog shows the right
684
-	 * permission if the owner or the sender changes the permission
685
-	 *
686
-	 * @param string $id
687
-	 * @param array $notification
688
-	 * @return array
689
-	 * @throws AuthenticationFailedException
690
-	 * @throws BadRequestException
691
-	 */
692
-	protected function updateResharePermissions($id, array $notification) {
693
-		throw new HintException('Updating reshares not allowed');
694
-	}
695
-
696
-	/**
697
-	 * translate OCM Permissions to Nextcloud permissions
698
-	 *
699
-	 * @param array $ocmPermissions
700
-	 * @return int
701
-	 * @throws BadRequestException
702
-	 */
703
-	protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
704
-		$ncPermissions = 0;
705
-		foreach ($ocmPermissions as $permission) {
706
-			switch (strtolower($permission)) {
707
-				case 'read':
708
-					$ncPermissions += Constants::PERMISSION_READ;
709
-					break;
710
-				case 'write':
711
-					$ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
712
-					break;
713
-				case 'share':
714
-					$ncPermissions += Constants::PERMISSION_SHARE;
715
-					break;
716
-				default:
717
-					throw new BadRequestException(['permission']);
718
-			}
719
-		}
720
-
721
-		return $ncPermissions;
722
-	}
723
-
724
-	/**
725
-	 * update permissions in database
726
-	 *
727
-	 * @param IShare $share
728
-	 * @param int $permissions
729
-	 */
730
-	protected function updatePermissionsInDatabase(IShare $share, $permissions) {
731
-		$query = $this->connection->getQueryBuilder();
732
-		$query->update('share')
733
-			->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
734
-			->set('permissions', $query->createNamedParameter($permissions))
735
-			->execute();
736
-	}
737
-
738
-
739
-	/**
740
-	 * get file
741
-	 *
742
-	 * @param string $user
743
-	 * @param int $fileSource
744
-	 * @return array with internal path of the file and a absolute link to it
745
-	 */
746
-	private function getFile($user, $fileSource) {
747
-		\OC_Util::setupFS($user);
748
-
749
-		try {
750
-			$file = Filesystem::getPath($fileSource);
751
-		} catch (NotFoundException $e) {
752
-			$file = null;
753
-		}
754
-		$args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file];
755
-		$link = Util::linkToAbsolute('files', 'index.php', $args);
756
-
757
-		return [$file, $link];
758
-	}
759
-
760
-	/**
761
-	 * check if we are the initiator or the owner of a re-share and return the correct UID
762
-	 *
763
-	 * @param IShare $share
764
-	 * @return string
765
-	 */
766
-	protected function getCorrectUid(IShare $share) {
767
-		if ($this->userManager->userExists($share->getShareOwner())) {
768
-			return $share->getShareOwner();
769
-		}
770
-
771
-		return $share->getSharedBy();
772
-	}
773
-
774
-
775
-
776
-	/**
777
-	 * check if we got the right share
778
-	 *
779
-	 * @param IShare $share
780
-	 * @param string $token
781
-	 * @return bool
782
-	 * @throws AuthenticationFailedException
783
-	 */
784
-	protected function verifyShare(IShare $share, $token) {
785
-		if (
786
-			$share->getShareType() === IShare::TYPE_REMOTE &&
787
-			$share->getToken() === $token
788
-		) {
789
-			return true;
790
-		}
791
-
792
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
793
-			try {
794
-				$knownShare = $this->shareManager->getShareByToken($token);
795
-				if ($knownShare->getId() === $share->getId()) {
796
-					return true;
797
-				}
798
-			} catch (ShareNotFound $e) {
799
-			}
800
-		}
801
-
802
-		throw new AuthenticationFailedException();
803
-	}
804
-
805
-
806
-
807
-	/**
808
-	 * check if server-to-server sharing is enabled
809
-	 *
810
-	 * @param bool $incoming
811
-	 * @return bool
812
-	 */
813
-	private function isS2SEnabled($incoming = false) {
814
-		$result = $this->appManager->isEnabledForUser('files_sharing');
815
-
816
-		if ($incoming) {
817
-			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
818
-		} else {
819
-			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
820
-		}
821
-
822
-		return $result;
823
-	}
824
-
825
-
826
-	/**
827
-	 * get the supported share types, e.g. "user", "group", etc.
828
-	 *
829
-	 * @return array
830
-	 *
831
-	 * @since 14.0.0
832
-	 */
833
-	public function getSupportedShareTypes() {
834
-		return ['user', 'group'];
835
-	}
67
+    /** @var IAppManager */
68
+    private $appManager;
69
+
70
+    /** @var FederatedShareProvider */
71
+    private $federatedShareProvider;
72
+
73
+    /** @var AddressHandler */
74
+    private $addressHandler;
75
+
76
+    /** @var ILogger */
77
+    private $logger;
78
+
79
+    /** @var IUserManager */
80
+    private $userManager;
81
+
82
+    /** @var IManager */
83
+    private $shareManager;
84
+
85
+    /** @var ICloudIdManager */
86
+    private $cloudIdManager;
87
+
88
+    /** @var IActivityManager */
89
+    private $activityManager;
90
+
91
+    /** @var INotificationManager */
92
+    private $notificationManager;
93
+
94
+    /** @var IURLGenerator */
95
+    private $urlGenerator;
96
+
97
+    /** @var ICloudFederationFactory */
98
+    private $cloudFederationFactory;
99
+
100
+    /** @var ICloudFederationProviderManager */
101
+    private $cloudFederationProviderManager;
102
+
103
+    /** @var IDBConnection */
104
+    private $connection;
105
+
106
+    /** @var IGroupManager */
107
+    private $groupManager;
108
+
109
+    /** @var IConfig */
110
+    private $config;
111
+
112
+    /**
113
+     * CloudFederationProvider constructor.
114
+     *
115
+     * @param IAppManager $appManager
116
+     * @param FederatedShareProvider $federatedShareProvider
117
+     * @param AddressHandler $addressHandler
118
+     * @param ILogger $logger
119
+     * @param IUserManager $userManager
120
+     * @param IManager $shareManager
121
+     * @param ICloudIdManager $cloudIdManager
122
+     * @param IActivityManager $activityManager
123
+     * @param INotificationManager $notificationManager
124
+     * @param IURLGenerator $urlGenerator
125
+     * @param ICloudFederationFactory $cloudFederationFactory
126
+     * @param ICloudFederationProviderManager $cloudFederationProviderManager
127
+     * @param IDBConnection $connection
128
+     * @param IGroupManager $groupManager
129
+     */
130
+    public function __construct(IAppManager $appManager,
131
+                                FederatedShareProvider $federatedShareProvider,
132
+                                AddressHandler $addressHandler,
133
+                                ILogger $logger,
134
+                                IUserManager $userManager,
135
+                                IManager $shareManager,
136
+                                ICloudIdManager $cloudIdManager,
137
+                                IActivityManager $activityManager,
138
+                                INotificationManager $notificationManager,
139
+                                IURLGenerator $urlGenerator,
140
+                                ICloudFederationFactory $cloudFederationFactory,
141
+                                ICloudFederationProviderManager $cloudFederationProviderManager,
142
+                                IDBConnection $connection,
143
+                                IGroupManager $groupManager,
144
+                                IConfig $config
145
+    ) {
146
+        $this->appManager = $appManager;
147
+        $this->federatedShareProvider = $federatedShareProvider;
148
+        $this->addressHandler = $addressHandler;
149
+        $this->logger = $logger;
150
+        $this->userManager = $userManager;
151
+        $this->shareManager = $shareManager;
152
+        $this->cloudIdManager = $cloudIdManager;
153
+        $this->activityManager = $activityManager;
154
+        $this->notificationManager = $notificationManager;
155
+        $this->urlGenerator = $urlGenerator;
156
+        $this->cloudFederationFactory = $cloudFederationFactory;
157
+        $this->cloudFederationProviderManager = $cloudFederationProviderManager;
158
+        $this->connection = $connection;
159
+        $this->groupManager = $groupManager;
160
+        $this->config = $config;
161
+    }
162
+
163
+
164
+
165
+    /**
166
+     * @return string
167
+     */
168
+    public function getShareType() {
169
+        return 'file';
170
+    }
171
+
172
+    /**
173
+     * share received from another server
174
+     *
175
+     * @param ICloudFederationShare $share
176
+     * @return string provider specific unique ID of the share
177
+     *
178
+     * @throws ProviderCouldNotAddShareException
179
+     * @throws \OCP\AppFramework\QueryException
180
+     * @throws \OC\HintException
181
+     * @since 14.0.0
182
+     */
183
+    public function shareReceived(ICloudFederationShare $share) {
184
+        if (!$this->isS2SEnabled(true)) {
185
+            throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
186
+        }
187
+
188
+        $protocol = $share->getProtocol();
189
+        if ($protocol['name'] !== 'webdav') {
190
+            throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
191
+        }
192
+
193
+        [$ownerUid, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
194
+        // for backward compatibility make sure that the remote url stored in the
195
+        // database ends with a trailing slash
196
+        if (substr($remote, -1) !== '/') {
197
+            $remote = $remote . '/';
198
+        }
199
+
200
+        $token = $share->getShareSecret();
201
+        $name = $share->getResourceName();
202
+        $owner = $share->getOwnerDisplayName();
203
+        $sharedBy = $share->getSharedByDisplayName();
204
+        $shareWith = $share->getShareWith();
205
+        $remoteId = $share->getProviderId();
206
+        $sharedByFederatedId = $share->getSharedBy();
207
+        $ownerFederatedId = $share->getOwner();
208
+        $shareType = $this->mapShareTypeToNextcloud($share->getShareType());
209
+
210
+        // if no explicit information about the person who created the share was send
211
+        // we assume that the share comes from the owner
212
+        if ($sharedByFederatedId === null) {
213
+            $sharedBy = $owner;
214
+            $sharedByFederatedId = $ownerFederatedId;
215
+        }
216
+
217
+        if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
218
+            if (!Util::isValidFileName($name)) {
219
+                throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
220
+            }
221
+
222
+            // FIXME this should be a method in the user management instead
223
+            if ($shareType === IShare::TYPE_USER) {
224
+                $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
225
+                Util::emitHook(
226
+                    '\OCA\Files_Sharing\API\Server2Server',
227
+                    'preLoginNameUsedAsUserName',
228
+                    ['uid' => &$shareWith]
229
+                );
230
+                $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
231
+
232
+                if (!$this->userManager->userExists($shareWith)) {
233
+                    throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST);
234
+                }
235
+
236
+                \OC_Util::setupFS($shareWith);
237
+            }
238
+
239
+            if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
240
+                throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST);
241
+            }
242
+
243
+            $externalManager = new \OCA\Files_Sharing\External\Manager(
244
+                \OC::$server->getDatabaseConnection(),
245
+                Filesystem::getMountManager(),
246
+                Filesystem::getLoader(),
247
+                \OC::$server->getHTTPClientService(),
248
+                \OC::$server->getNotificationManager(),
249
+                \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
250
+                \OC::$server->getCloudFederationProviderManager(),
251
+                \OC::$server->getCloudFederationFactory(),
252
+                \OC::$server->getGroupManager(),
253
+                \OC::$server->getUserManager(),
254
+                $shareWith,
255
+                \OC::$server->query(IEventDispatcher::class)
256
+            );
257
+
258
+            try {
259
+                $externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId);
260
+                $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
261
+
262
+                if ($shareType === IShare::TYPE_USER) {
263
+                    $event = $this->activityManager->generateEvent();
264
+                    $event->setApp('files_sharing')
265
+                        ->setType('remote_share')
266
+                        ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
267
+                        ->setAffectedUser($shareWith)
268
+                        ->setObject('remote_share', $shareId, $name);
269
+                    \OC::$server->getActivityManager()->publish($event);
270
+                    $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
271
+                } else {
272
+                    $groupMembers = $this->groupManager->get($shareWith)->getUsers();
273
+                    foreach ($groupMembers as $user) {
274
+                        $event = $this->activityManager->generateEvent();
275
+                        $event->setApp('files_sharing')
276
+                            ->setType('remote_share')
277
+                            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
278
+                            ->setAffectedUser($user->getUID())
279
+                            ->setObject('remote_share', $shareId, $name);
280
+                        \OC::$server->getActivityManager()->publish($event);
281
+                        $this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name);
282
+                    }
283
+                }
284
+                return $shareId;
285
+            } catch (\Exception $e) {
286
+                $this->logger->logException($e, [
287
+                    'message' => 'Server can not add remote share.',
288
+                    'level' => ILogger::ERROR,
289
+                    'app' => 'files_sharing'
290
+                ]);
291
+                throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
292
+            }
293
+        }
294
+
295
+        throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
296
+    }
297
+
298
+    /**
299
+     * notification received from another server
300
+     *
301
+     * @param string $notificationType (e.g. SHARE_ACCEPTED)
302
+     * @param string $providerId id of the share
303
+     * @param array $notification payload of the notification
304
+     * @return array data send back to the sender
305
+     *
306
+     * @throws ActionNotSupportedException
307
+     * @throws AuthenticationFailedException
308
+     * @throws BadRequestException
309
+     * @throws \OC\HintException
310
+     * @since 14.0.0
311
+     */
312
+    public function notificationReceived($notificationType, $providerId, array $notification) {
313
+        switch ($notificationType) {
314
+            case 'SHARE_ACCEPTED':
315
+                return $this->shareAccepted($providerId, $notification);
316
+            case 'SHARE_DECLINED':
317
+                return $this->shareDeclined($providerId, $notification);
318
+            case 'SHARE_UNSHARED':
319
+                return $this->unshare($providerId, $notification);
320
+            case 'REQUEST_RESHARE':
321
+                return $this->reshareRequested($providerId, $notification);
322
+            case 'RESHARE_UNDO':
323
+                return $this->undoReshare($providerId, $notification);
324
+            case 'RESHARE_CHANGE_PERMISSION':
325
+                return $this->updateResharePermissions($providerId, $notification);
326
+        }
327
+
328
+
329
+        throw new BadRequestException([$notificationType]);
330
+    }
331
+
332
+    /**
333
+     * map OCM share type (strings) to Nextcloud internal share types (integer)
334
+     *
335
+     * @param string $shareType
336
+     * @return int
337
+     */
338
+    private function mapShareTypeToNextcloud($shareType) {
339
+        $result = IShare::TYPE_USER;
340
+        if ($shareType === 'group') {
341
+            $result = IShare::TYPE_GROUP;
342
+        }
343
+
344
+        return $result;
345
+    }
346
+
347
+    private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name): void {
348
+        $notification = $this->notificationManager->createNotification();
349
+        $notification->setApp('files_sharing')
350
+            ->setUser($shareWith)
351
+            ->setDateTime(new \DateTime())
352
+            ->setObject('remote_share', $shareId)
353
+            ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
354
+
355
+        $declineAction = $notification->createAction();
356
+        $declineAction->setLabel('decline')
357
+            ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
358
+        $notification->addAction($declineAction);
359
+
360
+        $acceptAction = $notification->createAction();
361
+        $acceptAction->setLabel('accept')
362
+            ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
363
+        $notification->addAction($acceptAction);
364
+
365
+        $this->notificationManager->notify($notification);
366
+    }
367
+
368
+    /**
369
+     * process notification that the recipient accepted a share
370
+     *
371
+     * @param string $id
372
+     * @param array $notification
373
+     * @return array
374
+     * @throws ActionNotSupportedException
375
+     * @throws AuthenticationFailedException
376
+     * @throws BadRequestException
377
+     * @throws \OC\HintException
378
+     */
379
+    private function shareAccepted($id, array $notification) {
380
+        if (!$this->isS2SEnabled()) {
381
+            throw new ActionNotSupportedException('Server does not support federated cloud sharing');
382
+        }
383
+
384
+        if (!isset($notification['sharedSecret'])) {
385
+            throw new BadRequestException(['sharedSecret']);
386
+        }
387
+
388
+        $token = $notification['sharedSecret'];
389
+
390
+        $share = $this->federatedShareProvider->getShareById($id);
391
+
392
+        $this->verifyShare($share, $token);
393
+        $this->executeAcceptShare($share);
394
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
395
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
396
+            $remoteId = $this->federatedShareProvider->getRemoteId($share);
397
+            $notification = $this->cloudFederationFactory->getCloudFederationNotification();
398
+            $notification->setMessage(
399
+                'SHARE_ACCEPTED',
400
+                'file',
401
+                $remoteId,
402
+                [
403
+                    'sharedSecret' => $token,
404
+                    'message' => 'Recipient accepted the re-share'
405
+                ]
406
+
407
+            );
408
+            $this->cloudFederationProviderManager->sendNotification($remote, $notification);
409
+        }
410
+
411
+        return [];
412
+    }
413
+
414
+    /**
415
+     * @param IShare $share
416
+     * @throws ShareNotFound
417
+     */
418
+    protected function executeAcceptShare(IShare $share) {
419
+        try {
420
+            $fileId = (int)$share->getNode()->getId();
421
+            [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
422
+        } catch (\Exception $e) {
423
+            throw new ShareNotFound();
424
+        }
425
+
426
+        $event = $this->activityManager->generateEvent();
427
+        $event->setApp('files_sharing')
428
+            ->setType('remote_share')
429
+            ->setAffectedUser($this->getCorrectUid($share))
430
+            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
431
+            ->setObject('files', $fileId, $file)
432
+            ->setLink($link);
433
+        $this->activityManager->publish($event);
434
+    }
435
+
436
+    /**
437
+     * process notification that the recipient declined a share
438
+     *
439
+     * @param string $id
440
+     * @param array $notification
441
+     * @return array
442
+     * @throws ActionNotSupportedException
443
+     * @throws AuthenticationFailedException
444
+     * @throws BadRequestException
445
+     * @throws ShareNotFound
446
+     * @throws \OC\HintException
447
+     *
448
+     */
449
+    protected function shareDeclined($id, array $notification) {
450
+        if (!$this->isS2SEnabled()) {
451
+            throw new ActionNotSupportedException('Server does not support federated cloud sharing');
452
+        }
453
+
454
+        if (!isset($notification['sharedSecret'])) {
455
+            throw new BadRequestException(['sharedSecret']);
456
+        }
457
+
458
+        $token = $notification['sharedSecret'];
459
+
460
+        $share = $this->federatedShareProvider->getShareById($id);
461
+
462
+        $this->verifyShare($share, $token);
463
+
464
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
465
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
466
+            $remoteId = $this->federatedShareProvider->getRemoteId($share);
467
+            $notification = $this->cloudFederationFactory->getCloudFederationNotification();
468
+            $notification->setMessage(
469
+                'SHARE_DECLINED',
470
+                'file',
471
+                $remoteId,
472
+                [
473
+                    'sharedSecret' => $token,
474
+                    'message' => 'Recipient declined the re-share'
475
+                ]
476
+
477
+            );
478
+            $this->cloudFederationProviderManager->sendNotification($remote, $notification);
479
+        }
480
+
481
+        $this->executeDeclineShare($share);
482
+
483
+        return [];
484
+    }
485
+
486
+    /**
487
+     * delete declined share and create a activity
488
+     *
489
+     * @param IShare $share
490
+     * @throws ShareNotFound
491
+     */
492
+    protected function executeDeclineShare(IShare $share) {
493
+        $this->federatedShareProvider->removeShareFromTable($share);
494
+
495
+        try {
496
+            $fileId = (int)$share->getNode()->getId();
497
+            [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
498
+        } catch (\Exception $e) {
499
+            throw new ShareNotFound();
500
+        }
501
+
502
+        $event = $this->activityManager->generateEvent();
503
+        $event->setApp('files_sharing')
504
+            ->setType('remote_share')
505
+            ->setAffectedUser($this->getCorrectUid($share))
506
+            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
507
+            ->setObject('files', $fileId, $file)
508
+            ->setLink($link);
509
+        $this->activityManager->publish($event);
510
+    }
511
+
512
+    /**
513
+     * received the notification that the owner unshared a file from you
514
+     *
515
+     * @param string $id
516
+     * @param array $notification
517
+     * @return array
518
+     * @throws AuthenticationFailedException
519
+     * @throws BadRequestException
520
+     */
521
+    private function undoReshare($id, array $notification) {
522
+        if (!isset($notification['sharedSecret'])) {
523
+            throw new BadRequestException(['sharedSecret']);
524
+        }
525
+        $token = $notification['sharedSecret'];
526
+
527
+        $share = $this->federatedShareProvider->getShareById($id);
528
+
529
+        $this->verifyShare($share, $token);
530
+        $this->federatedShareProvider->removeShareFromTable($share);
531
+        return [];
532
+    }
533
+
534
+    /**
535
+     * unshare file from self
536
+     *
537
+     * @param string $id
538
+     * @param array $notification
539
+     * @return array
540
+     * @throws ActionNotSupportedException
541
+     * @throws BadRequestException
542
+     */
543
+    private function unshare($id, array $notification) {
544
+        if (!$this->isS2SEnabled(true)) {
545
+            throw new ActionNotSupportedException("incoming shares disabled!");
546
+        }
547
+
548
+        if (!isset($notification['sharedSecret'])) {
549
+            throw new BadRequestException(['sharedSecret']);
550
+        }
551
+        $token = $notification['sharedSecret'];
552
+
553
+        $qb = $this->connection->getQueryBuilder();
554
+        $qb->select('*')
555
+            ->from('share_external')
556
+            ->where(
557
+                $qb->expr()->andX(
558
+                    $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
559
+                    $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
560
+                )
561
+            );
562
+
563
+        $result = $qb->execute();
564
+        $share = $result->fetch();
565
+        $result->closeCursor();
566
+
567
+        if ($token && $id && !empty($share)) {
568
+            $remote = $this->cleanupRemote($share['remote']);
569
+
570
+            $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
571
+            $mountpoint = $share['mountpoint'];
572
+            $user = $share['user'];
573
+
574
+            $qb = $this->connection->getQueryBuilder();
575
+            $qb->delete('share_external')
576
+                ->where(
577
+                    $qb->expr()->andX(
578
+                        $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
579
+                        $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
580
+                    )
581
+                );
582
+
583
+            $qb->execute();
584
+
585
+            // delete all child in case of a group share
586
+            $qb = $this->connection->getQueryBuilder();
587
+            $qb->delete('share_external')
588
+                ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
589
+            $qb->execute();
590
+
591
+            if ((int)$share['share_type'] === IShare::TYPE_USER) {
592
+                if ($share['accepted']) {
593
+                    $path = trim($mountpoint, '/');
594
+                } else {
595
+                    $path = trim($share['name'], '/');
596
+                }
597
+                $notification = $this->notificationManager->createNotification();
598
+                $notification->setApp('files_sharing')
599
+                    ->setUser($share['user'])
600
+                    ->setObject('remote_share', (int)$share['id']);
601
+                $this->notificationManager->markProcessed($notification);
602
+
603
+                $event = $this->activityManager->generateEvent();
604
+                $event->setApp('files_sharing')
605
+                    ->setType('remote_share')
606
+                    ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
607
+                    ->setAffectedUser($user)
608
+                    ->setObject('remote_share', (int)$share['id'], $path);
609
+                \OC::$server->getActivityManager()->publish($event);
610
+            }
611
+        }
612
+
613
+        return [];
614
+    }
615
+
616
+    private function cleanupRemote($remote) {
617
+        $remote = substr($remote, strpos($remote, '://') + 3);
618
+
619
+        return rtrim($remote, '/');
620
+    }
621
+
622
+    /**
623
+     * recipient of a share request to re-share the file with another user
624
+     *
625
+     * @param string $id
626
+     * @param array $notification
627
+     * @return array
628
+     * @throws AuthenticationFailedException
629
+     * @throws BadRequestException
630
+     * @throws ProviderCouldNotAddShareException
631
+     * @throws ShareNotFound
632
+     */
633
+    protected function reshareRequested($id, array $notification) {
634
+        if (!isset($notification['sharedSecret'])) {
635
+            throw new BadRequestException(['sharedSecret']);
636
+        }
637
+        $token = $notification['sharedSecret'];
638
+
639
+        if (!isset($notification['shareWith'])) {
640
+            throw new BadRequestException(['shareWith']);
641
+        }
642
+        $shareWith = $notification['shareWith'];
643
+
644
+        if (!isset($notification['senderId'])) {
645
+            throw new BadRequestException(['senderId']);
646
+        }
647
+        $senderId = $notification['senderId'];
648
+
649
+        $share = $this->federatedShareProvider->getShareById($id);
650
+
651
+        // We have to respect the default share permissions
652
+        $permissions = $share->getPermissions() & (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
653
+        $share->setPermissions($permissions);
654
+
655
+        // don't allow to share a file back to the owner
656
+        try {
657
+            [$user, $remote] = $this->addressHandler->splitUserRemote($shareWith);
658
+            $owner = $share->getShareOwner();
659
+            $currentServer = $this->addressHandler->generateRemoteURL();
660
+            if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
661
+                throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
662
+            }
663
+        } catch (\Exception $e) {
664
+            throw new ProviderCouldNotAddShareException($e->getMessage());
665
+        }
666
+
667
+        $this->verifyShare($share, $token);
668
+
669
+        // check if re-sharing is allowed
670
+        if ($share->getPermissions() & Constants::PERMISSION_SHARE) {
671
+            // the recipient of the initial share is now the initiator for the re-share
672
+            $share->setSharedBy($share->getSharedWith());
673
+            $share->setSharedWith($shareWith);
674
+            $result = $this->federatedShareProvider->create($share);
675
+            $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
676
+            return ['token' => $result->getToken(), 'providerId' => $result->getId()];
677
+        } else {
678
+            throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
679
+        }
680
+    }
681
+
682
+    /**
683
+     * update permission of a re-share so that the share dialog shows the right
684
+     * permission if the owner or the sender changes the permission
685
+     *
686
+     * @param string $id
687
+     * @param array $notification
688
+     * @return array
689
+     * @throws AuthenticationFailedException
690
+     * @throws BadRequestException
691
+     */
692
+    protected function updateResharePermissions($id, array $notification) {
693
+        throw new HintException('Updating reshares not allowed');
694
+    }
695
+
696
+    /**
697
+     * translate OCM Permissions to Nextcloud permissions
698
+     *
699
+     * @param array $ocmPermissions
700
+     * @return int
701
+     * @throws BadRequestException
702
+     */
703
+    protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
704
+        $ncPermissions = 0;
705
+        foreach ($ocmPermissions as $permission) {
706
+            switch (strtolower($permission)) {
707
+                case 'read':
708
+                    $ncPermissions += Constants::PERMISSION_READ;
709
+                    break;
710
+                case 'write':
711
+                    $ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
712
+                    break;
713
+                case 'share':
714
+                    $ncPermissions += Constants::PERMISSION_SHARE;
715
+                    break;
716
+                default:
717
+                    throw new BadRequestException(['permission']);
718
+            }
719
+        }
720
+
721
+        return $ncPermissions;
722
+    }
723
+
724
+    /**
725
+     * update permissions in database
726
+     *
727
+     * @param IShare $share
728
+     * @param int $permissions
729
+     */
730
+    protected function updatePermissionsInDatabase(IShare $share, $permissions) {
731
+        $query = $this->connection->getQueryBuilder();
732
+        $query->update('share')
733
+            ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
734
+            ->set('permissions', $query->createNamedParameter($permissions))
735
+            ->execute();
736
+    }
737
+
738
+
739
+    /**
740
+     * get file
741
+     *
742
+     * @param string $user
743
+     * @param int $fileSource
744
+     * @return array with internal path of the file and a absolute link to it
745
+     */
746
+    private function getFile($user, $fileSource) {
747
+        \OC_Util::setupFS($user);
748
+
749
+        try {
750
+            $file = Filesystem::getPath($fileSource);
751
+        } catch (NotFoundException $e) {
752
+            $file = null;
753
+        }
754
+        $args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file];
755
+        $link = Util::linkToAbsolute('files', 'index.php', $args);
756
+
757
+        return [$file, $link];
758
+    }
759
+
760
+    /**
761
+     * check if we are the initiator or the owner of a re-share and return the correct UID
762
+     *
763
+     * @param IShare $share
764
+     * @return string
765
+     */
766
+    protected function getCorrectUid(IShare $share) {
767
+        if ($this->userManager->userExists($share->getShareOwner())) {
768
+            return $share->getShareOwner();
769
+        }
770
+
771
+        return $share->getSharedBy();
772
+    }
773
+
774
+
775
+
776
+    /**
777
+     * check if we got the right share
778
+     *
779
+     * @param IShare $share
780
+     * @param string $token
781
+     * @return bool
782
+     * @throws AuthenticationFailedException
783
+     */
784
+    protected function verifyShare(IShare $share, $token) {
785
+        if (
786
+            $share->getShareType() === IShare::TYPE_REMOTE &&
787
+            $share->getToken() === $token
788
+        ) {
789
+            return true;
790
+        }
791
+
792
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
793
+            try {
794
+                $knownShare = $this->shareManager->getShareByToken($token);
795
+                if ($knownShare->getId() === $share->getId()) {
796
+                    return true;
797
+                }
798
+            } catch (ShareNotFound $e) {
799
+            }
800
+        }
801
+
802
+        throw new AuthenticationFailedException();
803
+    }
804
+
805
+
806
+
807
+    /**
808
+     * check if server-to-server sharing is enabled
809
+     *
810
+     * @param bool $incoming
811
+     * @return bool
812
+     */
813
+    private function isS2SEnabled($incoming = false) {
814
+        $result = $this->appManager->isEnabledForUser('files_sharing');
815
+
816
+        if ($incoming) {
817
+            $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
818
+        } else {
819
+            $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
820
+        }
821
+
822
+        return $result;
823
+    }
824
+
825
+
826
+    /**
827
+     * get the supported share types, e.g. "user", "group", etc.
828
+     *
829
+     * @return array
830
+     *
831
+     * @since 14.0.0
832
+     */
833
+    public function getSupportedShareTypes() {
834
+        return ['user', 'group'];
835
+    }
836 836
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
 		// for backward compatibility make sure that the remote url stored in the
195 195
 		// database ends with a trailing slash
196 196
 		if (substr($remote, -1) !== '/') {
197
-			$remote = $remote . '/';
197
+			$remote = $remote.'/';
198 198
 		}
199 199
 
200 200
 		$token = $share->getShareSecret();
@@ -221,23 +221,23 @@  discard block
 block discarded – undo
221 221
 
222 222
 			// FIXME this should be a method in the user management instead
223 223
 			if ($shareType === IShare::TYPE_USER) {
224
-				$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
224
+				$this->logger->debug('shareWith before, '.$shareWith, ['app' => 'files_sharing']);
225 225
 				Util::emitHook(
226 226
 					'\OCA\Files_Sharing\API\Server2Server',
227 227
 					'preLoginNameUsedAsUserName',
228 228
 					['uid' => &$shareWith]
229 229
 				);
230
-				$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
230
+				$this->logger->debug('shareWith after, '.$shareWith, ['app' => 'files_sharing']);
231 231
 
232 232
 				if (!$this->userManager->userExists($shareWith)) {
233
-					throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST);
233
+					throw new ProviderCouldNotAddShareException('User does not exists', '', Http::STATUS_BAD_REQUEST);
234 234
 				}
235 235
 
236 236
 				\OC_Util::setupFS($shareWith);
237 237
 			}
238 238
 
239 239
 			if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
240
-				throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST);
240
+				throw new ProviderCouldNotAddShareException('Group does not exists', '', Http::STATUS_BAD_REQUEST);
241 241
 			}
242 242
 
243 243
 			$externalManager = new \OCA\Files_Sharing\External\Manager(
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
 			);
257 257
 
258 258
 			try {
259
-				$externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId);
259
+				$externalManager->addShare($remote, $token, '', $name, $owner, $shareType, false, $shareWith, $remoteId);
260 260
 				$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
261 261
 
262 262
 				if ($shareType === IShare::TYPE_USER) {
@@ -288,7 +288,7 @@  discard block
 block discarded – undo
288 288
 					'level' => ILogger::ERROR,
289 289
 					'app' => 'files_sharing'
290 290
 				]);
291
-				throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
291
+				throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from '.$remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
292 292
 			}
293 293
 		}
294 294
 
@@ -354,12 +354,12 @@  discard block
 block discarded – undo
354 354
 
355 355
 		$declineAction = $notification->createAction();
356 356
 		$declineAction->setLabel('decline')
357
-			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
357
+			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/'.$shareId)), 'DELETE');
358 358
 		$notification->addAction($declineAction);
359 359
 
360 360
 		$acceptAction = $notification->createAction();
361 361
 		$acceptAction->setLabel('accept')
362
-			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
362
+			->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/'.$shareId)), 'POST');
363 363
 		$notification->addAction($acceptAction);
364 364
 
365 365
 		$this->notificationManager->notify($notification);
@@ -417,7 +417,7 @@  discard block
 block discarded – undo
417 417
 	 */
418 418
 	protected function executeAcceptShare(IShare $share) {
419 419
 		try {
420
-			$fileId = (int)$share->getNode()->getId();
420
+			$fileId = (int) $share->getNode()->getId();
421 421
 			[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
422 422
 		} catch (\Exception $e) {
423 423
 			throw new ShareNotFound();
@@ -493,7 +493,7 @@  discard block
 block discarded – undo
493 493
 		$this->federatedShareProvider->removeShareFromTable($share);
494 494
 
495 495
 		try {
496
-			$fileId = (int)$share->getNode()->getId();
496
+			$fileId = (int) $share->getNode()->getId();
497 497
 			[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
498 498
 		} catch (\Exception $e) {
499 499
 			throw new ShareNotFound();
@@ -585,10 +585,10 @@  discard block
 block discarded – undo
585 585
 			// delete all child in case of a group share
586 586
 			$qb = $this->connection->getQueryBuilder();
587 587
 			$qb->delete('share_external')
588
-				->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
588
+				->where($qb->expr()->eq('parent', $qb->createNamedParameter((int) $share['id'])));
589 589
 			$qb->execute();
590 590
 
591
-			if ((int)$share['share_type'] === IShare::TYPE_USER) {
591
+			if ((int) $share['share_type'] === IShare::TYPE_USER) {
592 592
 				if ($share['accepted']) {
593 593
 					$path = trim($mountpoint, '/');
594 594
 				} else {
@@ -597,7 +597,7 @@  discard block
 block discarded – undo
597 597
 				$notification = $this->notificationManager->createNotification();
598 598
 				$notification->setApp('files_sharing')
599 599
 					->setUser($share['user'])
600
-					->setObject('remote_share', (int)$share['id']);
600
+					->setObject('remote_share', (int) $share['id']);
601 601
 				$this->notificationManager->markProcessed($notification);
602 602
 
603 603
 				$event = $this->activityManager->generateEvent();
@@ -605,7 +605,7 @@  discard block
 block discarded – undo
605 605
 					->setType('remote_share')
606 606
 					->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
607 607
 					->setAffectedUser($user)
608
-					->setObject('remote_share', (int)$share['id'], $path);
608
+					->setObject('remote_share', (int) $share['id'], $path);
609 609
 				\OC::$server->getActivityManager()->publish($event);
610 610
 			}
611 611
 		}
@@ -649,7 +649,7 @@  discard block
 block discarded – undo
649 649
 		$share = $this->federatedShareProvider->getShareById($id);
650 650
 
651 651
 		// We have to respect the default share permissions
652
-		$permissions = $share->getPermissions() & (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
652
+		$permissions = $share->getPermissions() & (int) $this->config->getAppValue('core', 'shareapi_default_permissions', (string) Constants::PERMISSION_ALL);
653 653
 		$share->setPermissions($permissions);
654 654
 
655 655
 		// don't allow to share a file back to the owner
@@ -658,7 +658,7 @@  discard block
 block discarded – undo
658 658
 			$owner = $share->getShareOwner();
659 659
 			$currentServer = $this->addressHandler->generateRemoteURL();
660 660
 			if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
661
-				throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
661
+				throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: '.$id);
662 662
 			}
663 663
 		} catch (\Exception $e) {
664 664
 			throw new ProviderCouldNotAddShareException($e->getMessage());
@@ -672,10 +672,10 @@  discard block
 block discarded – undo
672 672
 			$share->setSharedBy($share->getSharedWith());
673 673
 			$share->setSharedWith($shareWith);
674 674
 			$result = $this->federatedShareProvider->create($share);
675
-			$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
675
+			$this->federatedShareProvider->storeRemoteId((int) $result->getId(), $senderId);
676 676
 			return ['token' => $result->getToken(), 'providerId' => $result->getId()];
677 677
 		} else {
678
-			throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
678
+			throw new ProviderCouldNotAddShareException('resharing not allowed for share: '.$id);
679 679
 		}
680 680
 	}
681 681
 
Please login to merge, or discard this patch.