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

CloudFederationProviderFiles::reshareRequested()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 10
nop 2
dl 0
loc 45
rs 8.2666
c 0
b 0
f 0
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