Passed
Push — master ( 3eb5ac...514185 )
by Roeland
15:00
created

ShareController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 15
dl 0
loc 28
rs 9.8666
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) 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 Georg Ehrke <[email protected]>
9
 * @author Joas Schilling <[email protected]>
10
 * @author Lukas Reschke <[email protected]>
11
 * @author Maxence Lange <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Piotr Filiciak <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Roeland Jago Douma <[email protected]>
16
 * @author Sascha Sambale <[email protected]>
17
 * @author Thomas Müller <[email protected]>
18
 * @author Vincent Petry <[email protected]>
19
 *
20
 * @license AGPL-3.0
21
 *
22
 * This code is free software: you can redistribute it and/or modify
23
 * it under the terms of the GNU Affero General Public License, version 3,
24
 * as published by the Free Software Foundation.
25
 *
26
 * This program is distributed in the hope that it will be useful,
27
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29
 * GNU Affero General Public License for more details.
30
 *
31
 * You should have received a copy of the GNU Affero General Public License, version 3,
32
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
33
 *
34
 */
35
36
namespace OCA\Files_Sharing\Controller;
37
38
use OC\Security\CSP\ContentSecurityPolicy;
39
use OC_Files;
40
use OC_Util;
41
use OCA\FederatedFileSharing\FederatedShareProvider;
42
use OCP\AppFramework\AuthPublicShareController;
43
use OCP\AppFramework\Http\Template\SimpleMenuAction;
44
use OCP\AppFramework\Http\Template\ExternalShareMenuAction;
45
use OCP\AppFramework\Http\Template\LinkMenuAction;
46
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
47
use OCP\Defaults;
48
use OCP\IL10N;
49
use OCP\Template;
50
use OCP\Share;
51
use OCP\IRequest;
52
use OCP\AppFramework\Http\TemplateResponse;
53
use OCP\AppFramework\Http\NotFoundResponse;
54
use OCP\IURLGenerator;
55
use OCP\IConfig;
56
use OCP\ILogger;
57
use OCP\IUserManager;
58
use OCP\ISession;
59
use OCP\IPreview;
60
use OCA\Files_Sharing\Activity\Providers\Downloads;
61
use OCP\Files\NotFoundException;
62
use OCP\Files\IRootFolder;
63
use OCP\Share\Exceptions\ShareNotFound;
64
use OCP\Util;
65
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
66
use Symfony\Component\EventDispatcher\GenericEvent;
67
use OCP\Share\IManager as ShareManager;
68
69
/**
70
 * Class ShareController
71
 *
72
 * @package OCA\Files_Sharing\Controllers
73
 */
74
class ShareController extends AuthPublicShareController {
75
76
	/** @var IConfig */
77
	protected $config;
78
	/** @var IUserManager */
79
	protected $userManager;
80
	/** @var ILogger */
81
	protected $logger;
82
	/** @var \OCP\Activity\IManager */
83
	protected $activityManager;
84
	/** @var IPreview */
85
	protected $previewManager;
86
	/** @var IRootFolder */
87
	protected $rootFolder;
88
	/** @var FederatedShareProvider */
89
	protected $federatedShareProvider;
90
	/** @var EventDispatcherInterface */
91
	protected $eventDispatcher;
92
	/** @var IL10N */
93
	protected $l10n;
94
	/** @var Defaults */
95
	protected $defaults;
96
	/** @var ShareManager */
97
	protected $shareManager;
98
99
	/** @var Share\IShare */
100
	protected $share;
101
102
	/**
103
	 * @param string $appName
104
	 * @param IRequest $request
105
	 * @param IConfig $config
106
	 * @param IURLGenerator $urlGenerator
107
	 * @param IUserManager $userManager
108
	 * @param ILogger $logger
109
	 * @param \OCP\Activity\IManager $activityManager
110
	 * @param \OCP\Share\IManager $shareManager
111
	 * @param ISession $session
112
	 * @param IPreview $previewManager
113
	 * @param IRootFolder $rootFolder
114
	 * @param FederatedShareProvider $federatedShareProvider
115
	 * @param EventDispatcherInterface $eventDispatcher
116
	 * @param IL10N $l10n
117
	 * @param Defaults $defaults
118
	 */
119
	public function __construct(string $appName,
120
								IRequest $request,
121
								IConfig $config,
122
								IURLGenerator $urlGenerator,
123
								IUserManager $userManager,
124
								ILogger $logger,
125
								\OCP\Activity\IManager $activityManager,
126
								ShareManager $shareManager,
127
								ISession $session,
128
								IPreview $previewManager,
129
								IRootFolder $rootFolder,
130
								FederatedShareProvider $federatedShareProvider,
131
								EventDispatcherInterface $eventDispatcher,
132
								IL10N $l10n,
133
								Defaults $defaults) {
134
		parent::__construct($appName, $request, $session, $urlGenerator);
135
136
		$this->config = $config;
137
		$this->userManager = $userManager;
138
		$this->logger = $logger;
139
		$this->activityManager = $activityManager;
140
		$this->previewManager = $previewManager;
141
		$this->rootFolder = $rootFolder;
142
		$this->federatedShareProvider = $federatedShareProvider;
143
		$this->eventDispatcher = $eventDispatcher;
144
		$this->l10n = $l10n;
145
		$this->defaults = $defaults;
146
		$this->shareManager = $shareManager;
147
	}
148
149
	/**
150
	 * @PublicPage
151
	 * @NoCSRFRequired
152
	 *
153
	 * Show the authentication page
154
	 * The form has to submit to the authenticate method route
155
	 */
156
	public function showAuthenticate(): TemplateResponse {
157
		$templateParameters = ['share' => $this->share];
158
159
		$event = new GenericEvent(null, $templateParameters);
160
		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event);
161
162
		$response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
163
		if ($this->share->getSendPasswordByTalk()) {
164
			$csp = new ContentSecurityPolicy();
165
			$csp->addAllowedConnectDomain('*');
166
			$csp->addAllowedMediaDomain('blob:');
167
			$csp->allowEvalScript(true);
168
			$response->setContentSecurityPolicy($csp);
169
		}
170
171
		return $response;
172
	}
173
174
	/**
175
	 * The template to show when authentication failed
176
	 */
177
	protected function showAuthFailed(): TemplateResponse {
178
		$templateParameters = ['share' => $this->share, 'wrongpw' => true];
179
180
		$event = new GenericEvent(null, $templateParameters);
181
		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event);
182
183
		$response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
184
		if ($this->share->getSendPasswordByTalk()) {
185
			$csp = new ContentSecurityPolicy();
186
			$csp->addAllowedConnectDomain('*');
187
			$csp->addAllowedMediaDomain('blob:');
188
			$csp->allowEvalScript(true);
189
			$response->setContentSecurityPolicy($csp);
190
		}
191
192
		return $response;
193
	}
194
195
	protected function verifyPassword(string $password): bool {
196
		return $this->shareManager->checkPassword($this->share, $password);
197
	}
198
199
	protected function getPasswordHash(): string {
200
		return $this->share->getPassword();
201
	}
202
203
	public function isValidToken(): bool {
204
		try {
205
			$this->share = $this->shareManager->getShareByToken($this->getToken());
206
		} catch (ShareNotFound $e) {
207
			return false;
208
		}
209
210
		return true;
211
	}
212
213
	protected function isPasswordProtected(): bool {
214
		return $this->share->getPassword() !== null;
215
	}
216
217
	protected function authSucceeded() {
218
		// For share this was always set so it is still used in other apps
219
		$this->session->set('public_link_authenticated', (string)$this->share->getId());
220
	}
221
222
	protected function authFailed() {
223
		$this->emitAccessShareHook($this->share, 403, 'Wrong password');
224
	}
225
226
	/**
227
	 * throws hooks when a share is attempted to be accessed
228
	 *
229
	 * @param \OCP\Share\IShare|string $share the Share instance if available,
230
	 * otherwise token
231
	 * @param int $errorCode
232
	 * @param string $errorMessage
233
	 * @throws \OC\HintException
234
	 * @throws \OC\ServerNotAvailableException
235
	 */
236
	protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
237
		$itemType = $itemSource = $uidOwner = '';
238
		$token = $share;
239
		$exception = null;
240
		if($share instanceof \OCP\Share\IShare) {
241
			try {
242
				$token = $share->getToken();
243
				$uidOwner = $share->getSharedBy();
244
				$itemType = $share->getNodeType();
245
				$itemSource = $share->getNodeId();
246
			} catch (\Exception $e) {
247
				// we log what we know and pass on the exception afterwards
248
				$exception = $e;
249
			}
250
		}
251
		\OC_Hook::emit(Share::class, 'share_link_access', [
252
			'itemType' => $itemType,
253
			'itemSource' => $itemSource,
254
			'uidOwner' => $uidOwner,
255
			'token' => $token,
256
			'errorCode' => $errorCode,
257
			'errorMessage' => $errorMessage,
258
		]);
259
		if(!is_null($exception)) {
260
			throw $exception;
261
		}
262
	}
263
264
	/**
265
	 * Validate the permissions of the share
266
	 *
267
	 * @param Share\IShare $share
268
	 * @return bool
269
	 */
270
	private function validateShare(\OCP\Share\IShare $share) {
271
		return $share->getNode()->isReadable() && $share->getNode()->isShareable();
272
	}
273
274
	/**
275
	 * @PublicPage
276
	 * @NoCSRFRequired
277
	 *
278
279
	 * @param string $path
280
	 * @return TemplateResponse
281
	 * @throws NotFoundException
282
	 * @throws \Exception
283
	 */
284
	public function showShare($path = ''): TemplateResponse {
285
		\OC_User::setIncognitoMode(true);
286
287
		// Check whether share exists
288
		try {
289
			$share = $this->shareManager->getShareByToken($this->getToken());
290
		} catch (ShareNotFound $e) {
291
			$this->emitAccessShareHook($this->getToken(), 404, 'Share not found');
292
			throw new NotFoundException();
293
		}
294
295
		if (!$this->validateShare($share)) {
296
			throw new NotFoundException();
297
		}
298
		// We can't get the path of a file share
299
		try {
300
			if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
301
				$this->emitAccessShareHook($share, 404, 'Share not found');
302
				throw new NotFoundException();
303
			}
304
		} catch (\Exception $e) {
305
			$this->emitAccessShareHook($share, 404, 'Share not found');
306
			throw $e;
307
		}
308
309
		$shareTmpl = [];
310
		$shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
311
		$shareTmpl['owner'] = $share->getShareOwner();
312
		$shareTmpl['filename'] = $share->getNode()->getName();
313
		$shareTmpl['directory_path'] = $share->getTarget();
314
		$shareTmpl['note'] = $share->getNote();
315
		$shareTmpl['mimetype'] = $share->getNode()->getMimetype();
316
		$shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
317
		$shareTmpl['dirToken'] = $this->getToken();
318
		$shareTmpl['sharingToken'] = $this->getToken();
319
		$shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
320
		$shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
321
		$shareTmpl['dir'] = '';
322
		$shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
323
		$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
324
		$shareTmpl['hideDownload'] = $share->getHideDownload();
325
326
		// Show file list
327
		$hideFileList = false;
328
		if ($share->getNode() instanceof \OCP\Files\Folder) {
329
			/** @var \OCP\Files\Folder $rootFolder */
330
			$rootFolder = $share->getNode();
331
332
			try {
333
				$folderNode = $rootFolder->get($path);
334
			} catch (\OCP\Files\NotFoundException $e) {
335
				$this->emitAccessShareHook($share, 404, 'Share not found');
336
				throw new NotFoundException();
337
			}
338
339
			$shareTmpl['dir'] = $rootFolder->getRelativePath($folderNode->getPath());
340
341
			/*
342
			 * The OC_Util methods require a view. This just uses the node API
343
			 */
344
			$freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
345
			if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
346
				$freeSpace = max($freeSpace, 0);
347
			} else {
348
				$freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
349
			}
350
351
			$hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ);
352
			$maxUploadFilesize = $freeSpace;
353
354
			$folder = new Template('files', 'list', '');
355
			$folder->assign('dir', $rootFolder->getRelativePath($folderNode->getPath()));
356
			$folder->assign('dirToken', $this->getToken());
357
			$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
358
			$folder->assign('isPublic', true);
359
			$folder->assign('hideFileList', $hideFileList);
360
			$folder->assign('publicUploadEnabled', 'no');
361
			$folder->assign('showgridview', true);
362
			$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
363
			$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
0 ignored issues
show
Bug introduced by
It seems like $maxUploadFilesize can also be of type double; however, parameter $bytes of OCP\Util::humanFileSize() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

363
			$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize(/** @scrutinizer ignore-type */ $maxUploadFilesize));
Loading history...
364
			$folder->assign('freeSpace', $freeSpace);
365
			$folder->assign('usedSpacePercent', 0);
366
			$folder->assign('trash', false);
367
			$shareTmpl['folder'] = $folder->fetchPage();
368
		}
369
370
		$shareTmpl['hideFileList'] = $hideFileList;
371
		$shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
372
		$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $this->getToken()]);
373
		$shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $this->getToken()]);
374
		$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
375
		$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
376
		$shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
377
		$shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
378
		$shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
379
		$shareTmpl['previewURL'] = $shareTmpl['downloadURL'];
380
		$ogPreview = '';
381
		if ($shareTmpl['previewSupported']) {
382
			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview',
383
				['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 'token' => $shareTmpl['dirToken']]);
384
			$ogPreview = $shareTmpl['previewImage'];
385
386
			// We just have direct previews for image files
387
			if ($share->getNode()->getMimePart() === 'image') {
388
				$shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $this->getToken()]);
389
390
				$ogPreview = $shareTmpl['previewURL'];
391
392
				//Whatapp is kind of picky about their size requirements
393
				if ($this->request->isUserAgent(['/^WhatsApp/'])) {
394
					$ogPreview = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', [
395
						'token' => $this->getToken(),
396
						'x' => 256,
397
						'y' => 256,
398
						'a' => true,
399
					]);
400
				}
401
			}
402
		} else {
403
			$shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
404
			$ogPreview = $shareTmpl['previewImage'];
405
		}
406
407
		// Load files we need
408
		\OCP\Util::addScript('files', 'file-upload');
409
		\OCP\Util::addStyle('files_sharing', 'publicView');
410
		\OCP\Util::addScript('files_sharing', 'public');
411
		\OCP\Util::addScript('files_sharing', 'templates');
412
		\OCP\Util::addScript('files_sharing', 'public_note');
413
		\OCP\Util::addScript('files', 'fileactions');
414
		\OCP\Util::addScript('files', 'fileactionsmenu');
415
		\OCP\Util::addScript('files', 'jquery.fileupload');
416
		\OCP\Util::addScript('files_sharing', 'files_drop');
417
418
		if (isset($shareTmpl['folder'])) {
419
			// JS required for folders
420
			\OCP\Util::addStyle('files', 'merged');
421
			\OCP\Util::addScript('files', 'filesummary');
422
			\OCP\Util::addScript('files', 'templates');
423
			\OCP\Util::addScript('files', 'breadcrumb');
424
			\OCP\Util::addScript('files', 'fileinfomodel');
425
			\OCP\Util::addScript('files', 'newfilemenu');
426
			\OCP\Util::addScript('files', 'files');
427
			\OCP\Util::addScript('files', 'filemultiselectmenu');
428
			\OCP\Util::addScript('files', 'filelist');
429
			\OCP\Util::addScript('files', 'keyboardshortcuts');
430
		}
431
432
		// OpenGraph Support: http://ogp.me/
433
		\OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]);
434
		\OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]);
435
		\OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
436
		\OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
437
		\OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
438
		\OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]);
439
440
		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts');
441
442
		$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
0 ignored issues
show
Deprecated Code introduced by
The class OCP\AppFramework\Http\ContentSecurityPolicy has been deprecated: 14.0.0 Use one of our stricter CSP policies ( Ignorable by Annotation )

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

442
		$csp = /** @scrutinizer ignore-deprecated */ new \OCP\AppFramework\Http\ContentSecurityPolicy();
Loading history...
443
		$csp->addAllowedFrameDomain('\'self\'');
444
445
		$response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl);
446
		$response->setHeaderTitle($shareTmpl['filename']);
447
		$response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['displayName']]));
448
		if (!$share->getHideDownload()) {
449
			$response->setHeaderActions([
450
				new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0),
451
				new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']),
452
				new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']),
453
				new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['displayName'], $shareTmpl['filename']),
454
			]);
455
		}
456
457
		$response->setContentSecurityPolicy($csp);
458
459
		$this->emitAccessShareHook($share);
460
461
		return $response;
462
	}
463
464
	/**
465
	 * @PublicPage
466
	 * @NoCSRFRequired
467
	 *
468
	 * @param string $token
469
	 * @param string $files
470
	 * @param string $path
471
	 * @param string $downloadStartSecret
472
	 * @return void|\OCP\AppFramework\Http\Response
473
	 * @throws NotFoundException
474
	 */
475
	public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
476
		\OC_User::setIncognitoMode(true);
477
478
		$share = $this->shareManager->getShareByToken($token);
479
480
		if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
481
			return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
0 ignored issues
show
Bug introduced by
'Share is read-only' of type string is incompatible with the type array|object expected by parameter $data of OCP\AppFramework\Http\DataResponse::__construct(). ( Ignorable by Annotation )

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

481
			return new \OCP\AppFramework\Http\DataResponse(/** @scrutinizer ignore-type */ 'Share is read-only');
Loading history...
482
		}
483
484
		$files_list = null;
485
		if (!is_null($files)) { // download selected files
486
			$files_list = json_decode($files);
487
			// in case we get only a single file
488
			if ($files_list === null) {
489
				$files_list = [$files];
490
			}
491
			// Just in case $files is a single int like '1234'
492
			if (!is_array($files_list)) {
493
				$files_list = [$files_list];
494
			}
495
		}
496
497
498
		if (!$this->validateShare($share)) {
499
			throw new NotFoundException();
500
		}
501
502
		$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
503
		$originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
504
505
506
		// Single file share
507
		if ($share->getNode() instanceof \OCP\Files\File) {
508
			// Single file download
509
			$this->singleFileDownloaded($share, $share->getNode());
510
		}
511
		// Directory share
512
		else {
513
			/** @var \OCP\Files\Folder $node */
514
			$node = $share->getNode();
515
516
			// Try to get the path
517
			if ($path !== '') {
518
				try {
519
					$node = $node->get($path);
520
				} catch (NotFoundException $e) {
521
					$this->emitAccessShareHook($share, 404, 'Share not found');
522
					return new NotFoundResponse();
523
				}
524
			}
525
526
			$originalSharePath = $userFolder->getRelativePath($node->getPath());
527
528
			if ($node instanceof \OCP\Files\File) {
529
				// Single file download
530
				$this->singleFileDownloaded($share, $share->getNode());
531
			} else if (!empty($files_list)) {
532
				$this->fileListDownloaded($share, $files_list, $node);
533
			} else {
534
				// The folder is downloaded
535
				$this->singleFileDownloaded($share, $share->getNode());
536
			}
537
		}
538
539
		/* FIXME: We should do this all nicely in OCP */
540
		OC_Util::tearDownFS();
541
		OC_Util::setupFS($share->getShareOwner());
542
543
		/**
544
		 * this sets a cookie to be able to recognize the start of the download
545
		 * the content must not be longer than 32 characters and must only contain
546
		 * alphanumeric characters
547
		 */
548
		if (!empty($downloadStartSecret)
549
			&& !isset($downloadStartSecret[32])
550
			&& preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
551
552
			// FIXME: set on the response once we use an actual app framework response
553
			setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
554
		}
555
556
		$this->emitAccessShareHook($share);
557
558
		$server_params = array( 'head' => $this->request->getMethod() === 'HEAD' );
559
560
		/**
561
		 * Http range requests support
562
		 */
563
		if (isset($_SERVER['HTTP_RANGE'])) {
564
			$server_params['range'] = $this->request->getHeader('Range');
565
		}
566
567
		// download selected files
568
		if (!is_null($files) && $files !== '') {
569
			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
570
			// after dispatching the request which results in a "Cannot modify header information" notice.
571
			OC_Files::get($originalSharePath, $files_list, $server_params);
0 ignored issues
show
Bug introduced by
It seems like $files_list can also be of type array<integer,mixed> and array<integer,string>; however, parameter $files of OC_Files::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

571
			OC_Files::get($originalSharePath, /** @scrutinizer ignore-type */ $files_list, $server_params);
Loading history...
572
			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...
573
		} else {
574
			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
575
			// after dispatching the request which results in a "Cannot modify header information" notice.
576
			OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
577
			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...
578
		}
579
	}
580
581
	/**
582
	 * create activity for every downloaded file
583
	 *
584
	 * @param Share\IShare $share
585
	 * @param array $files_list
586
	 * @param \OCP\Files\Folder $node
587
	 */
588
	protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
589
		foreach ($files_list as $file) {
590
			$subNode = $node->get($file);
591
			$this->singleFileDownloaded($share, $subNode);
592
		}
593
594
	}
595
596
	/**
597
	 * create activity if a single file was downloaded from a link share
598
	 *
599
	 * @param Share\IShare $share
600
	 */
601
	protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
602
603
		$fileId = $node->getId();
604
605
		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
606
		$userNodeList = $userFolder->getById($fileId);
607
		$userNode = $userNodeList[0];
608
		$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
609
		$userPath = $userFolder->getRelativePath($userNode->getPath());
610
		$ownerPath = $ownerFolder->getRelativePath($node->getPath());
611
612
		$parameters = [$userPath];
613
614
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
615
			if ($node instanceof \OCP\Files\File) {
616
				$subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
617
			} else {
618
				$subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
619
			}
620
			$parameters[] = $share->getSharedWith();
621
		} else {
622
			if ($node instanceof \OCP\Files\File) {
623
				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
624
			} else {
625
				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
626
			}
627
		}
628
629
		$this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
630
631
		if ($share->getShareOwner() !== $share->getSharedBy()) {
632
			$parameters[0] = $ownerPath;
633
			$this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
634
		}
635
	}
636
637
	/**
638
	 * publish activity
639
	 *
640
	 * @param string $subject
641
	 * @param array $parameters
642
	 * @param string $affectedUser
643
	 * @param int $fileId
644
	 * @param string $filePath
645
	 */
646
	protected function publishActivity($subject,
647
										array $parameters,
648
										$affectedUser,
649
										$fileId,
650
										$filePath) {
651
652
		$event = $this->activityManager->generateEvent();
653
		$event->setApp('files_sharing')
654
			->setType('public_links')
655
			->setSubject($subject, $parameters)
656
			->setAffectedUser($affectedUser)
657
			->setObject('files', $fileId, $filePath);
658
		$this->activityManager->publish($event);
659
	}
660
661
662
}
663