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

CloudFederationProviderFiles::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 12
dl 0
loc 26
rs 9.504
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2018 Bjoern Schiessle <[email protected]>
4
 *
5
 * @license GNU AGPL version 3 or any later version
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as
9
 * published by the Free Software Foundation, either version 3 of the
10
 * License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
namespace OCA\FederatedFileSharing\OCM;
23
24
use OC\AppFramework\Http;
25
use OC\Files\Filesystem;
26
use OCA\Files_Sharing\Activity\Providers\RemoteShares;
27
use OCA\FederatedFileSharing\AddressHandler;
28
use OCA\FederatedFileSharing\FederatedShareProvider;
29
use OCP\Activity\IManager as IActivityManager;
30
use OCP\App\IAppManager;
31
use OCP\Constants;
32
use OCP\Federation\Exceptions\ActionNotSupportedException;
33
use OCP\Federation\Exceptions\AuthenticationFailedException;
34
use OCP\Federation\Exceptions\BadRequestException;
35
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
36
use OCP\Federation\ICloudFederationFactory;
37
use OCP\Federation\ICloudFederationProvider;
38
use OCP\Federation\ICloudFederationProviderManager;
39
use OCP\Federation\ICloudFederationShare;
40
use OCP\Federation\ICloudIdManager;
41
use OCP\Files\NotFoundException;
42
use OCP\IDBConnection;
43
use OCP\ILogger;
44
use OCP\IURLGenerator;
45
use OCP\IUserManager;
46
use OCP\Notification\IManager as INotificationManager;
47
use OCP\Share\Exceptions\ShareNotFound;
48
use OCP\Share\IShare;
49
use OCP\Util;
50
51
class CloudFederationProviderFiles implements ICloudFederationProvider {
52
53
	/** @var IAppManager */
54
	private $appManager;
55
56
	/** @var FederatedShareProvider */
57
	private $federatedShareProvider;
58
59
	/** @var AddressHandler */
60
	private $addressHandler;
61
62
	/** @var ILogger */
63
	private $logger;
64
65
	/** @var IUserManager */
66
	private $userManager;
67
68
	/** @var ICloudIdManager */
69
	private $cloudIdManager;
70
71
	/** @var IActivityManager */
72
	private $activityManager;
73
74
	/** @var INotificationManager */
75
	private $notificationManager;
76
77
	/** @var IURLGenerator */
78
	private $urlGenerator;
79
80
	/** @var ICloudFederationFactory */
81
	private $cloudFederationFactory;
82
83
	/** @var ICloudFederationProviderManager */
84
	private $cloudFederationProviderManager;
85
86
	/** @var IDBConnection */
87
	private $connection;
88
89
	/**
90
	 * CloudFederationProvider constructor.
91
	 *
92
	 * @param IAppManager $appManager
93
	 * @param FederatedShareProvider $federatedShareProvider
94
	 * @param AddressHandler $addressHandler
95
	 * @param ILogger $logger
96
	 * @param IUserManager $userManager
97
	 * @param ICloudIdManager $cloudIdManager
98
	 * @param IActivityManager $activityManager
99
	 * @param INotificationManager $notificationManager
100
	 * @param IURLGenerator $urlGenerator
101
	 * @param ICloudFederationFactory $cloudFederationFactory
102
	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
103
	 * @param IDBConnection $connection
104
	 */
105
	public function __construct(IAppManager $appManager,
106
								FederatedShareProvider $federatedShareProvider,
107
								AddressHandler $addressHandler,
108
								ILogger $logger,
109
								IUserManager $userManager,
110
								ICloudIdManager $cloudIdManager,
111
								IActivityManager $activityManager,
112
								INotificationManager $notificationManager,
113
								IURLGenerator $urlGenerator,
114
								ICloudFederationFactory $cloudFederationFactory,
115
								ICloudFederationProviderManager $cloudFederationProviderManager,
116
								IDBConnection $connection
117
	) {
118
		$this->appManager = $appManager;
119
		$this->federatedShareProvider = $federatedShareProvider;
120
		$this->addressHandler = $addressHandler;
121
		$this->logger = $logger;
122
		$this->userManager = $userManager;
123
		$this->cloudIdManager = $cloudIdManager;
124
		$this->activityManager = $activityManager;
125
		$this->notificationManager = $notificationManager;
126
		$this->urlGenerator = $urlGenerator;
127
		$this->cloudFederationFactory = $cloudFederationFactory;
128
		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
129
		$this->connection = $connection;
130
	}
131
132
133
134
	/**
135
	 * @return string
136
	 */
137
	public function getShareType() {
138
		return 'file';
139
	}
140
141
	/**
142
	 * share received from another server
143
	 *
144
	 * @param ICloudFederationShare $share
145
	 * @return string provider specific unique ID of the share
146
	 *
147
	 * @throws ProviderCouldNotAddShareException
148
	 * @throws \OCP\AppFramework\QueryException
149
	 * @throws \OC\HintException
150
	 * @since 14.0.0
151
	 */
152
	public function shareReceived(ICloudFederationShare $share) {
153
154
		if (!$this->isS2SEnabled(true)) {
155
			throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
156
		}
157
158
		$protocol = $share->getProtocol();
159
		if ($protocol['name'] !== 'webdav') {
160
			throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
161
		}
162
163
		list($ownerUid, $remote) = $this->addressHandler->splitUserRemote($share->getOwner());
0 ignored issues
show
Unused Code introduced by
The assignment to $ownerUid is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
164
		// for backward compatibility make sure that the remote url stored in the
165
		// database ends with a trailing slash
166
		if (substr($remote, -1) !== '/') {
167
			$remote = $remote . '/';
168
		}
169
170
		$token = $share->getShareSecret();
171
		$name = $share->getResourceName();
172
		$owner = $share->getOwnerDisplayName();
173
		$sharedBy = $share->getSharedByDisplayName();
0 ignored issues
show
Unused Code introduced by
$sharedBy is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
174
		$shareWith = $share->getShareWith();
175
		$remoteId = $share->getProviderId();
176
		$sharedByFederatedId = $share->getSharedBy();
177
		$ownerFederatedId = $share->getOwner();
178
179
		// if no explicit information about the person who created the share was send
180
		// we assume that the share comes from the owner
181
		if ($sharedByFederatedId === null) {
182
			$sharedBy = $owner;
0 ignored issues
show
Unused Code introduced by
$sharedBy is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
183
			$sharedByFederatedId = $ownerFederatedId;
184
		}
185
186
		if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
187
188
			if (!Util::isValidFileName($name)) {
189
				throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
190
			}
191
192
			// FIXME this should be a method in the user management instead
193
			$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
194
			Util::emitHook(
195
				'\OCA\Files_Sharing\API\Server2Server',
196
				'preLoginNameUsedAsUserName',
197
				array('uid' => &$shareWith)
198
			);
199
			$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
200
201
			if (!$this->userManager->userExists($shareWith)) {
202
				throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST);
203
			}
204
205
			\OC_Util::setupFS($shareWith);
206
207
			$externalManager = new \OCA\Files_Sharing\External\Manager(
208
				\OC::$server->getDatabaseConnection(),
209
				Filesystem::getMountManager(),
210
				Filesystem::getLoader(),
211
				\OC::$server->getHTTPClientService(),
212
				\OC::$server->getNotificationManager(),
213
				\OC::$server->query(\OCP\OCS\IDiscoveryService::class),
214
				\OC::$server->getCloudFederationProviderManager(),
215
				\OC::$server->getCloudFederationFactory(),
216
				$shareWith
217
			);
218
219
			try {
220
				$externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
221
				$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
222
223
				$event = $this->activityManager->generateEvent();
224
				$event->setApp('files_sharing')
225
					->setType('remote_share')
226
					->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
227
					->setAffectedUser($shareWith)
228
					->setObject('remote_share', (int)$shareId, $name);
229
				\OC::$server->getActivityManager()->publish($event);
230
231
				$notification = $this->notificationManager->createNotification();
232
				$notification->setApp('files_sharing')
233
					->setUser($shareWith)
234
					->setDateTime(new \DateTime())
235
					->setObject('remote_share', $shareId)
236
					->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
237
238
				$declineAction = $notification->createAction();
239
				$declineAction->setLabel('decline')
240
					->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
241
				$notification->addAction($declineAction);
242
243
				$acceptAction = $notification->createAction();
244
				$acceptAction->setLabel('accept')
245
					->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
246
				$notification->addAction($acceptAction);
247
248
				$this->notificationManager->notify($notification);
249
250
				return $shareId;
251
			} catch (\Exception $e) {
252
				$this->logger->logException($e, [
0 ignored issues
show
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
253
					'message' => 'Server can not add remote share.',
254
					'level' => ILogger::ERROR,
255
					'app' => 'files_sharing'
256
				]);
257
				throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR);
258
			}
259
		}
260
261
		throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
262
263
	}
264
265
	/**
266
	 * notification received from another server
267
	 *
268
	 * @param string $notificationType (e.g. SHARE_ACCEPTED)
269
	 * @param string $providerId id of the share
270
	 * @param array $notification payload of the notification
271
	 * @return array data send back to the sender
272
	 *
273
	 * @throws ActionNotSupportedException
274
	 * @throws AuthenticationFailedException
275
	 * @throws BadRequestException
276
	 * @throws \OC\HintException
277
	 * @since 14.0.0
278
	 */
279
	public function notificationReceived($notificationType, $providerId, array $notification) {
280
281
		switch ($notificationType) {
282
			case 'SHARE_ACCEPTED':
283
				return $this->shareAccepted($providerId, $notification);
284
			case 'SHARE_DECLINED':
285
				return $this->shareDeclined($providerId, $notification);
286
			case 'SHARE_UNSHARED':
287
				return $this->unshare($providerId, $notification);
288
			case 'REQUEST_RESHARE':
289
				return $this->reshareRequested($providerId, $notification);
290
			case 'RESHARE_UNDO':
291
				return $this->undoReshare($providerId, $notification);
292
			case 'RESHARE_CHANGE_PERMISSION':
293
				return $this->updateResharePermissions($providerId, $notification);
294
		}
295
296
297
		throw new BadRequestException([$notificationType]);
298
	}
299
300
	/**
301
	 * process notification that the recipient accepted a share
302
	 *
303
	 * @param string $id
304
	 * @param array $notification
305
	 * @return array
306
	 * @throws ActionNotSupportedException
307
	 * @throws AuthenticationFailedException
308
	 * @throws BadRequestException
309
	 * @throws \OC\HintException
310
	 */
311 View Code Duplication
	private function shareAccepted($id, array $notification) {
312
313
		if (!$this->isS2SEnabled()) {
314
			throw new ActionNotSupportedException('Server does not support federated cloud sharing');
315
		}
316
317
		if (!isset($notification['sharedSecret'])) {
318
			throw new BadRequestException(['sharedSecret']);
319
		}
320
321
		$token = $notification['sharedSecret'];
322
323
		$share = $this->federatedShareProvider->getShareById($id);
324
325
		$this->verifyShare($share, $token);
326
		$this->executeAcceptShare($share);
327
		if ($share->getShareOwner() !== $share->getSharedBy()) {
328
			list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
329
			$remoteId = $this->federatedShareProvider->getRemoteId($share);
330
			$notification = $this->cloudFederationFactory->getCloudFederationNotification();
331
			$notification->setMessage(
332
				'SHARE_ACCEPTED',
333
				'file',
334
				$remoteId,
335
				[
336
					'sharedSecret' => $token,
337
					'message' => 'Recipient accepted the re-share'
338
				]
339
340
			);
341
			$this->cloudFederationProviderManager->sendNotification($remote, $notification);
342
343
		}
344
345
		return [];
346
	}
347
348
	/**
349
	 * @param IShare $share
350
	 * @throws ShareNotFound
351
	 */
352 View Code Duplication
	protected function executeAcceptShare(IShare $share) {
353
		try {
354
			$fileId = (int)$share->getNode()->getId();
355
			list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
356
		} catch (\Exception $e) {
357
			throw new ShareNotFound();
358
		}
359
360
		$event = $this->activityManager->generateEvent();
361
		$event->setApp('files_sharing')
362
			->setType('remote_share')
363
			->setAffectedUser($this->getCorrectUid($share))
364
			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
365
			->setObject('files', $fileId, $file)
366
			->setLink($link);
367
		$this->activityManager->publish($event);
368
	}
369
370
	/**
371
	 * process notification that the recipient declined a share
372
	 *
373
	 * @param string $id
374
	 * @param array $notification
375
	 * @return array
376
	 * @throws ActionNotSupportedException
377
	 * @throws AuthenticationFailedException
378
	 * @throws BadRequestException
379
	 * @throws ShareNotFound
380
	 * @throws \OC\HintException
381
	 *
382
	 */
383 View Code Duplication
	protected function shareDeclined($id, array $notification) {
384
385
		if (!$this->isS2SEnabled()) {
386
			throw new ActionNotSupportedException('Server does not support federated cloud sharing');
387
		}
388
389
		if (!isset($notification['sharedSecret'])) {
390
			throw new BadRequestException(['sharedSecret']);
391
		}
392
393
		$token = $notification['sharedSecret'];
394
395
		$share = $this->federatedShareProvider->getShareById($id);
396
397
		$this->verifyShare($share, $token);
398
399
		if ($share->getShareOwner() !== $share->getSharedBy()) {
400
			list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
401
			$remoteId = $this->federatedShareProvider->getRemoteId($share);
402
			$notification = $this->cloudFederationFactory->getCloudFederationNotification();
403
			$notification->setMessage(
404
				'SHARE_DECLINED',
405
				'file',
406
				$remoteId,
407
				[
408
					'sharedSecret' => $token,
409
					'message' => 'Recipient declined the re-share'
410
				]
411
412
			);
413
			$this->cloudFederationProviderManager->sendNotification($remote, $notification);
414
		}
415
416
		$this->executeDeclineShare($share);
417
418
		return [];
419
420
	}
421
422
	/**
423
	 * delete declined share and create a activity
424
	 *
425
	 * @param IShare $share
426
	 * @throws ShareNotFound
427
	 */
428 View Code Duplication
	protected function executeDeclineShare(IShare $share) {
429
		$this->federatedShareProvider->removeShareFromTable($share);
430
431
		try {
432
			$fileId = (int)$share->getNode()->getId();
433
			list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
434
		} catch (\Exception $e) {
435
			throw new ShareNotFound();
436
		}
437
438
		$event = $this->activityManager->generateEvent();
439
		$event->setApp('files_sharing')
440
			->setType('remote_share')
441
			->setAffectedUser($this->getCorrectUid($share))
442
			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
443
			->setObject('files', $fileId, $file)
444
			->setLink($link);
445
		$this->activityManager->publish($event);
446
447
	}
448
449
	/**
450
	 * received the notification that the owner unshared a file from you
451
	 *
452
	 * @param string $id
453
	 * @param array $notification
454
	 * @return array
455
	 * @throws AuthenticationFailedException
456
	 * @throws BadRequestException
457
	 */
458
	private function undoReshare($id, array $notification) {
459
		if (!isset($notification['sharedSecret'])) {
460
			throw new BadRequestException(['sharedSecret']);
461
		}
462
		$token = $notification['sharedSecret'];
463
464
		$share = $this->federatedShareProvider->getShareById($id);
465
466
		$this->verifyShare($share, $token);
467
		$this->federatedShareProvider->removeShareFromTable($share);
468
		return [];
469
	}
470
471
	/**
472
	 * unshare file from self
473
	 *
474
	 * @param string $id
475
	 * @param array $notification
476
	 * @return array
477
	 * @throws ActionNotSupportedException
478
	 * @throws BadRequestException
479
	 */
480
	private function unshare($id, array $notification) {
481
482
		if (!$this->isS2SEnabled(true)) {
483
			throw new ActionNotSupportedException("incoming shares disabled!");
484
		}
485
486
		if (!isset($notification['sharedSecret'])) {
487
			throw new BadRequestException(['sharedSecret']);
488
		}
489
		$token = $notification['sharedSecret'];
490
491
		$qb = $this->connection->getQueryBuilder();
492
		$qb->select('*')
493
			->from('share_external')
494
			->where(
495
				$qb->expr()->andX(
496
					$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
497
					$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
498
				)
499
			);
500
501
		$result = $qb->execute();
502
		$share = $result->fetch();
503
		$result->closeCursor();
504
505
		if ($token && $id && !empty($share)) {
506
507
			$remote = $this->cleanupRemote($share['remote']);
508
509
			$owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
510
			$mountpoint = $share['mountpoint'];
511
			$user = $share['user'];
512
513
			$qb = $this->connection->getQueryBuilder();
514
			$qb->delete('share_external')
515
				->where(
516
					$qb->expr()->andX(
517
						$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
518
						$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
519
					)
520
				);
521
522
			$qb->execute();
523
524
			if ($share['accepted']) {
525
				$path = trim($mountpoint, '/');
526
			} else {
527
				$path = trim($share['name'], '/');
528
			}
529
530
			$notification = $this->notificationManager->createNotification();
531
			$notification->setApp('files_sharing')
532
				->setUser($share['user'])
533
				->setObject('remote_share', (int)$share['id']);
534
			$this->notificationManager->markProcessed($notification);
535
536
			$event = $this->activityManager->generateEvent();
537
			$event->setApp('files_sharing')
538
				->setType('remote_share')
539
				->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
540
				->setAffectedUser($user)
541
				->setObject('remote_share', (int)$share['id'], $path);
542
			\OC::$server->getActivityManager()->publish($event);
543
		}
544
545
		return [];
546
	}
547
548
	private function cleanupRemote($remote) {
549
		$remote = substr($remote, strpos($remote, '://') + 3);
550
551
		return rtrim($remote, '/');
552
	}
553
554
	/**
555
	 * recipient of a share request to re-share the file with another user
556
	 *
557
	 * @param string $id
558
	 * @param array $notification
559
	 * @return array
560
	 * @throws AuthenticationFailedException
561
	 * @throws BadRequestException
562
	 * @throws ProviderCouldNotAddShareException
563
	 * @throws ShareNotFound
564
	 */
565
	protected function reshareRequested($id, array $notification) {
566
567
		if (!isset($notification['sharedSecret'])) {
568
			throw new BadRequestException(['sharedSecret']);
569
		}
570
		$token = $notification['sharedSecret'];
571
572
		if (!isset($notification['shareWith'])) {
573
			throw new BadRequestException(['shareWith']);
574
		}
575
		$shareWith = $notification['shareWith'];
576
577
		if (!isset($notification['senderId'])) {
578
			throw new BadRequestException(['senderId']);
579
		}
580
		$senderId = $notification['senderId'];
581
582
		$share = $this->federatedShareProvider->getShareById($id);
583
		// don't allow to share a file back to the owner
584
		try {
585
			list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
586
			$owner = $share->getShareOwner();
587
			$currentServer = $this->addressHandler->generateRemoteURL();
588
			if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
589
				throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id);
590
			}
591
		} catch (\Exception $e) {
592
			throw new ProviderCouldNotAddShareException($e->getMessage());
593
		}
594
595
		$this->verifyShare($share, $token);
596
597
		// check if re-sharing is allowed
598
		if ($share->getPermissions() & Constants::PERMISSION_SHARE) {
599
			// the recipient of the initial share is now the initiator for the re-share
600
			$share->setSharedBy($share->getSharedWith());
601
			$share->setSharedWith($shareWith);
602
			$result = $this->federatedShareProvider->create($share);
603
			$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
604
			return ['token' => $result->getToken(), 'providerId' => $result->getId()];
605
		} else {
606
			throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
607
		}
608
609
	}
610
611
	/**
612
	 * update permission of a re-share so that the share dialog shows the right
613
	 * permission if the owner or the sender changes the permission
614
	 *
615
	 * @param string $id
616
	 * @param array $notification
617
	 * @return array
618
	 * @throws AuthenticationFailedException
619
	 * @throws BadRequestException
620
	 */
621
	protected function updateResharePermissions($id, array $notification) {
622
623
		if (!isset($notification['sharedSecret'])) {
624
			throw new BadRequestException(['sharedSecret']);
625
		}
626
		$token = $notification['sharedSecret'];
627
628
		if (!isset($notification['permission'])) {
629
			throw new BadRequestException(['permission']);
630
		}
631
		$ocmPermissions = $notification['permission'];
632
633
		$share = $this->federatedShareProvider->getShareById($id);
634
635
		$ncPermission = $this->ocmPermissions2ncPermissions($ocmPermissions);
636
637
		$this->verifyShare($share, $token);
638
		$this->updatePermissionsInDatabase($share, $ncPermission);
639
640
		return [];
641
	}
642
643
	/**
644
	 * translate OCM Permissions to Nextcloud permissions
645
	 *
646
	 * @param array $ocmPermissions
647
	 * @return int
648
	 * @throws BadRequestException
649
	 */
650
	protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
651
		$ncPermissions = 0;
652 View Code Duplication
		foreach($ocmPermissions as $permission) {
653
			switch (strtolower($permission)) {
654
				case 'read':
655
					$ncPermissions += Constants::PERMISSION_READ;
656
					break;
657
				case 'write':
658
					$ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
659
					break;
660
				case 'share':
661
					$ncPermissions += Constants::PERMISSION_SHARE;
662
					break;
663
				default:
664
					throw new BadRequestException(['permission']);
665
			}
666
667
		}
668
669
		return $ncPermissions;
670
	}
671
672
	/**
673
	 * update permissions in database
674
	 *
675
	 * @param IShare $share
676
	 * @param int $permissions
677
	 */
678
	protected function updatePermissionsInDatabase(IShare $share, $permissions) {
679
		$query = $this->connection->getQueryBuilder();
680
		$query->update('share')
681
			->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
682
			->set('permissions', $query->createNamedParameter($permissions))
683
			->execute();
684
	}
685
686
687
	/**
688
	 * get file
689
	 *
690
	 * @param string $user
691
	 * @param int $fileSource
692
	 * @return array with internal path of the file and a absolute link to it
693
	 */
694
	private function getFile($user, $fileSource) {
695
		\OC_Util::setupFS($user);
696
697
		try {
698
			$file = Filesystem::getPath($fileSource);
699
		} catch (NotFoundException $e) {
700
			$file = null;
701
		}
702
		$args = Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file);
703
		$link = Util::linkToAbsolute('files', 'index.php', $args);
704
705
		return [$file, $link];
706
707
	}
708
709
	/**
710
	 * check if we are the initiator or the owner of a re-share and return the correct UID
711
	 *
712
	 * @param IShare $share
713
	 * @return string
714
	 */
715
	protected function getCorrectUid(IShare $share) {
716
		if ($this->userManager->userExists($share->getShareOwner())) {
717
			return $share->getShareOwner();
718
		}
719
720
		return $share->getSharedBy();
721
	}
722
723
724
725
	/**
726
	 * check if we got the right share
727
	 *
728
	 * @param IShare $share
729
	 * @param string $token
730
	 * @return bool
731
	 * @throws AuthenticationFailedException
732
	 */
733
	protected function verifyShare(IShare $share, $token) {
734
		if (
735
			$share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
736
			$share->getToken() === $token
737
		) {
738
			return true;
739
		}
740
741
		throw new AuthenticationFailedException();
742
	}
743
744
745
746
	/**
747
	 * check if server-to-server sharing is enabled
748
	 *
749
	 * @param bool $incoming
750
	 * @return bool
751
	 */
752 View Code Duplication
	private function isS2SEnabled($incoming = false) {
753
754
		$result = $this->appManager->isEnabledForUser('files_sharing');
755
756
		if ($incoming) {
757
			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
758
		} else {
759
			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
760
		}
761
762
		return $result;
763
	}
764
765
766
	/**
767
	 * get the supported share types, e.g. "user", "group", etc.
768
	 *
769
	 * @return array
770
	 *
771
	 * @since 14.0.0
772
	 */
773
	public function getSupportedShareTypes() {
774
		return ['user'];
775
	}
776
}
777