Passed
Push — master ( 6f3c4f...d83ea2 )
by Blizzz
16:41 queued 12s
created

ShareController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
c 0
b 0
f 0
nc 1
nop 18
dl 0
loc 36
rs 9.7666

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) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Daniel Calviño Sánchez <[email protected]>
10
 * @author Georg Ehrke <[email protected]>
11
 * @author j3l11234 <[email protected]>
12
 * @author Joas Schilling <[email protected]>
13
 * @author John Molakvoæ <[email protected]>
14
 * @author Jonas Sulzer <[email protected]>
15
 * @author Julius Härtl <[email protected]>
16
 * @author Lukas Reschke <[email protected]>
17
 * @author MartB <[email protected]>
18
 * @author Maxence Lange <[email protected]>
19
 * @author Michael Weimann <[email protected]>
20
 * @author Morris Jobke <[email protected]>
21
 * @author Piotr Filiciak <[email protected]>
22
 * @author Robin Appelman <[email protected]>
23
 * @author Roeland Jago Douma <[email protected]>
24
 * @author Sascha Sambale <[email protected]>
25
 * @author Thomas Müller <[email protected]>
26
 * @author Vincent Petry <[email protected]>
27
 *
28
 * @license AGPL-3.0
29
 *
30
 * This code is free software: you can redistribute it and/or modify
31
 * it under the terms of the GNU Affero General Public License, version 3,
32
 * as published by the Free Software Foundation.
33
 *
34
 * This program is distributed in the hope that it will be useful,
35
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37
 * GNU Affero General Public License for more details.
38
 *
39
 * You should have received a copy of the GNU Affero General Public License, version 3,
40
 * along with this program. If not, see <http://www.gnu.org/licenses/>
41
 *
42
 */
43
namespace OCA\Files_Sharing\Controller;
44
45
use OC\Security\CSP\ContentSecurityPolicy;
46
use OC_Files;
47
use OC_Util;
48
use OCA\FederatedFileSharing\FederatedShareProvider;
49
use OCA\Files_Sharing\Activity\Providers\Downloads;
50
use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
51
use OCA\Files_Sharing\Event\ShareLinkAccessedEvent;
52
use OCA\Viewer\Event\LoadViewer;
0 ignored issues
show
Bug introduced by
The type OCA\Viewer\Event\LoadViewer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
53
use OCP\Accounts\IAccountManager;
54
use OCP\AppFramework\AuthPublicShareController;
55
use OCP\AppFramework\Http\NotFoundResponse;
56
use OCP\AppFramework\Http\Template\ExternalShareMenuAction;
57
use OCP\AppFramework\Http\Template\LinkMenuAction;
58
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
59
use OCP\AppFramework\Http\Template\SimpleMenuAction;
60
use OCP\AppFramework\Http\TemplateResponse;
61
use OCP\Defaults;
62
use OCP\EventDispatcher\IEventDispatcher;
63
use OCP\Files\Folder;
64
use OCP\Files\IRootFolder;
65
use OCP\Files\NotFoundException;
66
use OCP\IConfig;
67
use OCP\IL10N;
68
use OCP\ILogger;
69
use OCP\IPreview;
70
use OCP\IRequest;
71
use OCP\ISession;
72
use OCP\IURLGenerator;
73
use OCP\IUser;
74
use OCP\IUserManager;
75
use OCP\Security\ISecureRandom;
76
use OCP\Share;
77
use OCP\Share\Exceptions\ShareNotFound;
78
use OCP\Share\IManager as ShareManager;
79
use OCP\Share\IShare;
80
use OCP\Share\IPublicShareTemplateFactory;
81
use OCP\Template;
82
83
/**
84
 * Class ShareController
85
 *
86
 * @package OCA\Files_Sharing\Controllers
87
 */
88
class ShareController extends AuthPublicShareController {
89
	protected IConfig $config;
90
	protected IUserManager $userManager;
91
	protected ILogger $logger;
92
	protected \OCP\Activity\IManager $activityManager;
93
	protected IPreview $previewManager;
94
	protected IRootFolder $rootFolder;
95
	protected FederatedShareProvider $federatedShareProvider;
96
	protected IAccountManager $accountManager;
97
	protected IEventDispatcher $eventDispatcher;
98
	protected IL10N $l10n;
99
	protected Defaults $defaults;
100
	protected ShareManager $shareManager;
101
	protected ISecureRandom $secureRandom;
102
	protected ?Share\IShare $share = null;
103
	private IPublicShareTemplateFactory $publicShareTemplateFactory;
104
105
	public function __construct(
106
		string $appName,
107
		IRequest $request,
108
		IConfig $config,
109
		IURLGenerator $urlGenerator,
110
		IUserManager $userManager,
111
		ILogger $logger,
112
		\OCP\Activity\IManager $activityManager,
113
		ShareManager $shareManager,
114
		ISession $session,
115
		IPreview $previewManager,
116
		IRootFolder $rootFolder,
117
		FederatedShareProvider $federatedShareProvider,
118
		IAccountManager $accountManager,
119
		IEventDispatcher $eventDispatcher,
120
		IL10N $l10n,
121
		ISecureRandom $secureRandom,
122
		Defaults $defaults,
123
		IPublicShareTemplateFactory $publicShareTemplateFactory
124
	) {
125
		parent::__construct($appName, $request, $session, $urlGenerator);
126
127
		$this->config = $config;
128
		$this->userManager = $userManager;
129
		$this->logger = $logger;
130
		$this->activityManager = $activityManager;
131
		$this->previewManager = $previewManager;
132
		$this->rootFolder = $rootFolder;
133
		$this->federatedShareProvider = $federatedShareProvider;
134
		$this->accountManager = $accountManager;
135
		$this->eventDispatcher = $eventDispatcher;
136
		$this->l10n = $l10n;
137
		$this->secureRandom = $secureRandom;
138
		$this->defaults = $defaults;
139
		$this->shareManager = $shareManager;
140
		$this->publicShareTemplateFactory = $publicShareTemplateFactory;
141
	}
142
143
	public const SHARE_ACCESS = 'access';
144
	public const SHARE_AUTH = 'auth';
145
	public const SHARE_DOWNLOAD = 'download';
146
147
	/**
148
	 * @PublicPage
149
	 * @NoCSRFRequired
150
	 *
151
	 * Show the authentication page
152
	 * The form has to submit to the authenticate method route
153
	 */
154
	public function showAuthenticate(): TemplateResponse {
155
		$templateParameters = ['share' => $this->share];
156
157
		$this->eventDispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($this->share, BeforeTemplateRenderedEvent::SCOPE_PUBLIC_SHARE_AUTH));
158
159
		$response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
160
		if ($this->share->getSendPasswordByTalk()) {
0 ignored issues
show
Bug introduced by
The method getSendPasswordByTalk() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

160
		if ($this->share->/** @scrutinizer ignore-call */ getSendPasswordByTalk()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
			$csp = new ContentSecurityPolicy();
162
			$csp->addAllowedConnectDomain('*');
163
			$csp->addAllowedMediaDomain('blob:');
164
			$response->setContentSecurityPolicy($csp);
165
		}
166
167
		return $response;
168
	}
169
170
	/**
171
	 * The template to show when authentication failed
172
	 */
173
	protected function showAuthFailed(): TemplateResponse {
174
		$templateParameters = ['share' => $this->share, 'wrongpw' => true];
175
176
		$this->eventDispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($this->share, BeforeTemplateRenderedEvent::SCOPE_PUBLIC_SHARE_AUTH));
177
178
		$response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
179
		if ($this->share->getSendPasswordByTalk()) {
180
			$csp = new ContentSecurityPolicy();
181
			$csp->addAllowedConnectDomain('*');
182
			$csp->addAllowedMediaDomain('blob:');
183
			$response->setContentSecurityPolicy($csp);
184
		}
185
186
		return $response;
187
	}
188
189
	/**
190
	 * The template to show after user identification
191
	 */
192
	protected function showIdentificationResult(bool $success = false): TemplateResponse {
193
		$templateParameters = ['share' => $this->share, 'identityOk' => $success];
194
195
		$this->eventDispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($this->share, BeforeTemplateRenderedEvent::SCOPE_PUBLIC_SHARE_AUTH));
196
197
		$response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
198
		if ($this->share->getSendPasswordByTalk()) {
199
			$csp = new ContentSecurityPolicy();
200
			$csp->addAllowedConnectDomain('*');
201
			$csp->addAllowedMediaDomain('blob:');
202
			$response->setContentSecurityPolicy($csp);
203
		}
204
205
		return $response;
206
	}
207
208
	/**
209
	 * Validate the identity token of a public share
210
	 *
211
	 * @param ?string $identityToken
212
	 * @return bool
213
	 */
214
	protected function validateIdentity(?string $identityToken = null): bool {
215
216
		if ($this->share->getShareType() !== IShare::TYPE_EMAIL) {
217
			return false;
218
		}
219
220
		if ($identityToken === null || $this->share->getSharedWith() === null) {
221
			return false;
222
		}
223
224
		return $identityToken === $this->share->getSharedWith();
225
	}
226
227
	/**
228
	 * Generates a password for the share, respecting any password policy defined
229
	 */
230
	protected function generatePassword(): void {
231
		$event = new \OCP\Security\Events\GenerateSecurePasswordEvent();
232
		$this->eventDispatcher->dispatchTyped($event);
233
		$password = $event->getPassword() ?? $this->secureRandom->generate(20);
234
235
		$this->share->setPassword($password);
236
		$this->shareManager->updateShare($this->share);
237
	}
238
239
	protected function verifyPassword(string $password): bool {
240
		return $this->shareManager->checkPassword($this->share, $password);
241
	}
242
243
	protected function getPasswordHash(): string {
244
		return $this->share->getPassword();
245
	}
246
247
	public function isValidToken(): bool {
248
		try {
249
			$this->share = $this->shareManager->getShareByToken($this->getToken());
250
		} catch (ShareNotFound $e) {
251
			return false;
252
		}
253
254
		return true;
255
	}
256
257
	protected function isPasswordProtected(): bool {
258
		return $this->share->getPassword() !== null;
259
	}
260
261
	protected function authSucceeded() {
262
		// For share this was always set so it is still used in other apps
263
		$this->session->set('public_link_authenticated', (string)$this->share->getId());
264
	}
265
266
	protected function authFailed() {
267
		$this->emitAccessShareHook($this->share, 403, 'Wrong password');
268
		$this->emitShareAccessEvent($this->share, self::SHARE_AUTH, 403, 'Wrong password');
269
	}
270
271
	/**
272
	 * throws hooks when a share is attempted to be accessed
273
	 *
274
	 * @param \OCP\Share\IShare|string $share the Share instance if available,
275
	 * otherwise token
276
	 * @param int $errorCode
277
	 * @param string $errorMessage
278
	 *
279
	 * @throws \OCP\HintException
280
	 * @throws \OC\ServerNotAvailableException
281
	 *
282
	 * @deprecated use OCP\Files_Sharing\Event\ShareLinkAccessedEvent
283
	 */
284
	protected function emitAccessShareHook($share, int $errorCode = 200, string $errorMessage = '') {
285
		$itemType = $itemSource = $uidOwner = '';
286
		$token = $share;
287
		$exception = null;
288
		if ($share instanceof \OCP\Share\IShare) {
289
			try {
290
				$token = $share->getToken();
291
				$uidOwner = $share->getSharedBy();
292
				$itemType = $share->getNodeType();
293
				$itemSource = $share->getNodeId();
294
			} catch (\Exception $e) {
295
				// we log what we know and pass on the exception afterwards
296
				$exception = $e;
297
			}
298
		}
299
300
		\OC_Hook::emit(Share::class, 'share_link_access', [
301
			'itemType' => $itemType,
302
			'itemSource' => $itemSource,
303
			'uidOwner' => $uidOwner,
304
			'token' => $token,
305
			'errorCode' => $errorCode,
306
			'errorMessage' => $errorMessage
307
		]);
308
309
		if (!is_null($exception)) {
310
			throw $exception;
311
		}
312
	}
313
314
	/**
315
	 * Emit a ShareLinkAccessedEvent event when a share is accessed, downloaded, auth...
316
	 */
317
	protected function emitShareAccessEvent(IShare $share, string $step = '', int $errorCode = 200, string $errorMessage = ''): void {
318
		if ($step !== self::SHARE_ACCESS &&
319
			$step !== self::SHARE_AUTH &&
320
			$step !== self::SHARE_DOWNLOAD) {
321
			return;
322
		}
323
		$this->eventDispatcher->dispatchTyped(new ShareLinkAccessedEvent($share, $step, $errorCode, $errorMessage));
324
	}
325
326
	/**
327
	 * Validate the permissions of the share
328
	 *
329
	 * @param Share\IShare $share
330
	 * @return bool
331
	 */
332
	private function validateShare(\OCP\Share\IShare $share) {
333
		// If the owner is disabled no access to the link is granted
334
		$owner = $this->userManager->get($share->getShareOwner());
335
		if ($owner === null || !$owner->isEnabled()) {
336
			return false;
337
		}
338
339
		// If the initiator of the share is disabled no access is granted
340
		$initiator = $this->userManager->get($share->getSharedBy());
341
		if ($initiator === null || !$initiator->isEnabled()) {
342
			return false;
343
		}
344
345
		return $share->getNode()->isReadable() && $share->getNode()->isShareable();
346
	}
347
348
	/**
349
	 * @PublicPage
350
	 * @NoCSRFRequired
351
	 *
352
	 *
353
	 * @param string $path
354
	 * @return TemplateResponse
355
	 * @throws NotFoundException
356
	 * @throws \Exception
357
	 */
358
	public function showShare($path = ''): TemplateResponse {
359
		\OC_User::setIncognitoMode(true);
360
361
		// Check whether share exists
362
		try {
363
			$share = $this->shareManager->getShareByToken($this->getToken());
364
		} catch (ShareNotFound $e) {
365
			// The share does not exists, we do not emit an ShareLinkAccessedEvent
366
			$this->emitAccessShareHook($this->getToken(), 404, 'Share not found');
367
			throw new NotFoundException();
368
		}
369
370
		if (!$this->validateShare($share)) {
371
			throw new NotFoundException();
372
		}
373
374
		$shareNode = $share->getNode();
375
376
		try {
377
			$templateProvider = $this->publicShareTemplateFactory->getProvider($share);
378
			$response = $templateProvider->renderPage($share, $this->getToken(), $path);
379
		} catch (NotFoundException $e) {
380
			$this->emitAccessShareHook($share, 404, 'Share not found');
381
			$this->emitShareAccessEvent($share, ShareController::SHARE_ACCESS, 404, 'Share not found');
382
			throw new NotFoundException();
383
		}
384
385
		// We can't get the path of a file share
386
		try {
387
			if ($shareNode instanceof \OCP\Files\File && $path !== '') {
388
				$this->emitAccessShareHook($share, 404, 'Share not found');
389
				$this->emitShareAccessEvent($share, self::SHARE_ACCESS, 404, 'Share not found');
390
				throw new NotFoundException();
391
			}
392
		} catch (\Exception $e) {
393
			$this->emitAccessShareHook($share, 404, 'Share not found');
394
			$this->emitShareAccessEvent($share, self::SHARE_ACCESS, 404, 'Share not found');
395
			throw $e;
396
		}
397
398
399
		$this->emitAccessShareHook($share);
400
		$this->emitShareAccessEvent($share, self::SHARE_ACCESS);
401
402
		return $response;
403
	}
404
405
	/**
406
	 * @PublicPage
407
	 * @NoCSRFRequired
408
	 * @NoSameSiteCookieRequired
409
	 *
410
	 * @param string $token
411
	 * @param string $files
412
	 * @param string $path
413
	 * @param string $downloadStartSecret
414
	 * @return void|\OCP\AppFramework\Http\Response
415
	 * @throws NotFoundException
416
	 */
417
	public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
418
		\OC_User::setIncognitoMode(true);
419
420
		$share = $this->shareManager->getShareByToken($token);
421
422
		if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
423
			return new \OCP\AppFramework\Http\DataResponse('Share has no read permission');
424
		}
425
426
		$files_list = null;
427
		if (!is_null($files)) { // download selected files
428
			$files_list = json_decode($files);
429
			// in case we get only a single file
430
			if ($files_list === null) {
431
				$files_list = [$files];
432
			}
433
			// Just in case $files is a single int like '1234'
434
			if (!is_array($files_list)) {
435
				$files_list = [$files_list];
436
			}
437
		}
438
439
		if (!$this->validateShare($share)) {
440
			throw new NotFoundException();
441
		}
442
443
		$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
444
		$originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
445
446
447
		// Single file share
448
		if ($share->getNode() instanceof \OCP\Files\File) {
449
			// Single file download
450
			$this->singleFileDownloaded($share, $share->getNode());
451
		}
452
		// Directory share
453
		else {
454
			/** @var \OCP\Files\Folder $node */
455
			$node = $share->getNode();
456
457
			// Try to get the path
458
			if ($path !== '') {
459
				try {
460
					$node = $node->get($path);
461
				} catch (NotFoundException $e) {
462
					$this->emitAccessShareHook($share, 404, 'Share not found');
463
					$this->emitShareAccessEvent($share, self::SHARE_DOWNLOAD, 404, 'Share not found');
464
					return new NotFoundResponse();
465
				}
466
			}
467
468
			$originalSharePath = $userFolder->getRelativePath($node->getPath());
469
470
			if ($node instanceof \OCP\Files\File) {
471
				// Single file download
472
				$this->singleFileDownloaded($share, $share->getNode());
473
			} else {
474
				try {
475
					if (!empty($files_list)) {
476
						$this->fileListDownloaded($share, $files_list, $node);
477
					} else {
478
						// The folder is downloaded
479
						$this->singleFileDownloaded($share, $share->getNode());
480
					}
481
				} catch (NotFoundException $e) {
482
					return new NotFoundResponse();
483
				}
484
			}
485
		}
486
487
		/* FIXME: We should do this all nicely in OCP */
488
		OC_Util::tearDownFS();
489
		OC_Util::setupFS($share->getShareOwner());
490
491
		/**
492
		 * this sets a cookie to be able to recognize the start of the download
493
		 * the content must not be longer than 32 characters and must only contain
494
		 * alphanumeric characters
495
		 */
496
		if (!empty($downloadStartSecret)
497
			&& !isset($downloadStartSecret[32])
498
			&& preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
499
500
			// FIXME: set on the response once we use an actual app framework response
501
			setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
502
		}
503
504
		$this->emitAccessShareHook($share);
505
		$this->emitShareAccessEvent($share, self::SHARE_DOWNLOAD);
506
507
		$server_params = [ 'head' => $this->request->getMethod() === 'HEAD' ];
508
509
		/**
510
		 * Http range requests support
511
		 */
512
		if (isset($_SERVER['HTTP_RANGE'])) {
513
			$server_params['range'] = $this->request->getHeader('Range');
514
		}
515
516
		// download selected files
517
		if (!is_null($files) && $files !== '') {
518
			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
519
			// after dispatching the request which results in a "Cannot modify header information" notice.
520
			OC_Files::get($originalSharePath, $files_list, $server_params);
521
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
522
		} else {
523
			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
524
			// after dispatching the request which results in a "Cannot modify header information" notice.
525
			OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
526
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
527
		}
528
	}
529
530
	/**
531
	 * create activity for every downloaded file
532
	 *
533
	 * @param Share\IShare $share
534
	 * @param array $files_list
535
	 * @param \OCP\Files\Folder $node
536
	 * @throws NotFoundException when trying to download a folder or multiple files of a "hide download" share
537
	 */
538
	protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
539
		if ($share->getHideDownload() && count($files_list) > 1) {
540
			throw new NotFoundException('Downloading more than 1 file');
541
		}
542
543
		foreach ($files_list as $file) {
544
			$subNode = $node->get($file);
545
			$this->singleFileDownloaded($share, $subNode);
546
		}
547
	}
548
549
	/**
550
	 * create activity if a single file was downloaded from a link share
551
	 *
552
	 * @param Share\IShare $share
553
	 * @throws NotFoundException when trying to download a folder of a "hide download" share
554
	 */
555
	protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
556
		if ($share->getHideDownload() && $node instanceof Folder) {
557
			throw new NotFoundException('Downloading a folder');
558
		}
559
560
		$fileId = $node->getId();
561
562
		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
563
		$userNodeList = $userFolder->getById($fileId);
564
		$userNode = $userNodeList[0];
565
		$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
566
		$userPath = $userFolder->getRelativePath($userNode->getPath());
567
		$ownerPath = $ownerFolder->getRelativePath($node->getPath());
568
		$remoteAddress = $this->request->getRemoteAddress();
569
		$dateTime = new \DateTime();
570
		$dateTime = $dateTime->format('Y-m-d H');
571
		$remoteAddressHash = md5($dateTime . '-' . $remoteAddress);
572
573
		$parameters = [$userPath];
574
575
		if ($share->getShareType() === IShare::TYPE_EMAIL) {
576
			if ($node instanceof \OCP\Files\File) {
577
				$subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
578
			} else {
579
				$subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
580
			}
581
			$parameters[] = $share->getSharedWith();
582
		} else {
583
			if ($node instanceof \OCP\Files\File) {
584
				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
585
				$parameters[] = $remoteAddressHash;
586
			} else {
587
				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
588
				$parameters[] = $remoteAddressHash;
589
			}
590
		}
591
592
		$this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
593
594
		if ($share->getShareOwner() !== $share->getSharedBy()) {
595
			$parameters[0] = $ownerPath;
596
			$this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
597
		}
598
	}
599
600
	/**
601
	 * publish activity
602
	 *
603
	 * @param string $subject
604
	 * @param array $parameters
605
	 * @param string $affectedUser
606
	 * @param int $fileId
607
	 * @param string $filePath
608
	 */
609
	protected function publishActivity($subject,
610
										array $parameters,
611
										$affectedUser,
612
										$fileId,
613
										$filePath) {
614
		$event = $this->activityManager->generateEvent();
615
		$event->setApp('files_sharing')
616
			->setType('public_links')
617
			->setSubject($subject, $parameters)
618
			->setAffectedUser($affectedUser)
619
			->setObject('files', $fileId, $filePath);
620
		$this->activityManager->publish($event);
621
	}
622
}
623