Passed
Push — master ( defcbd...4114bc )
by Roeland
13:06 queued 12s
created
apps/files_sharing/lib/Controller/ShareController.php 1 patch
Indentation   +660 added lines, -660 removed lines patch added patch discarded remove patch
@@ -83,666 +83,666 @@
 block discarded – undo
83 83
  */
84 84
 class ShareController extends AuthPublicShareController {
85 85
 
86
-	/** @var IConfig */
87
-	protected $config;
88
-	/** @var IUserManager */
89
-	protected $userManager;
90
-	/** @var ILogger */
91
-	protected $logger;
92
-	/** @var \OCP\Activity\IManager */
93
-	protected $activityManager;
94
-	/** @var IPreview */
95
-	protected $previewManager;
96
-	/** @var IRootFolder */
97
-	protected $rootFolder;
98
-	/** @var FederatedShareProvider */
99
-	protected $federatedShareProvider;
100
-	/** @var IAccountManager */
101
-	protected $accountManager;
102
-	/** @var EventDispatcherInterface */
103
-	protected $eventDispatcher;
104
-	/** @var IL10N */
105
-	protected $l10n;
106
-	/** @var Defaults */
107
-	protected $defaults;
108
-	/** @var ShareManager */
109
-	protected $shareManager;
110
-
111
-	/** @var Share\IShare */
112
-	protected $share;
113
-
114
-	/**
115
-	 * @param string $appName
116
-	 * @param IRequest $request
117
-	 * @param IConfig $config
118
-	 * @param IURLGenerator $urlGenerator
119
-	 * @param IUserManager $userManager
120
-	 * @param ILogger $logger
121
-	 * @param \OCP\Activity\IManager $activityManager
122
-	 * @param \OCP\Share\IManager $shareManager
123
-	 * @param ISession $session
124
-	 * @param IPreview $previewManager
125
-	 * @param IRootFolder $rootFolder
126
-	 * @param FederatedShareProvider $federatedShareProvider
127
-	 * @param IAccountManager $accountManager
128
-	 * @param EventDispatcherInterface $eventDispatcher
129
-	 * @param IL10N $l10n
130
-	 * @param Defaults $defaults
131
-	 */
132
-	public function __construct(string $appName,
133
-								IRequest $request,
134
-								IConfig $config,
135
-								IURLGenerator $urlGenerator,
136
-								IUserManager $userManager,
137
-								ILogger $logger,
138
-								\OCP\Activity\IManager $activityManager,
139
-								ShareManager $shareManager,
140
-								ISession $session,
141
-								IPreview $previewManager,
142
-								IRootFolder $rootFolder,
143
-								FederatedShareProvider $federatedShareProvider,
144
-								IAccountManager $accountManager,
145
-								EventDispatcherInterface $eventDispatcher,
146
-								IL10N $l10n,
147
-								Defaults $defaults) {
148
-		parent::__construct($appName, $request, $session, $urlGenerator);
149
-
150
-		$this->config = $config;
151
-		$this->userManager = $userManager;
152
-		$this->logger = $logger;
153
-		$this->activityManager = $activityManager;
154
-		$this->previewManager = $previewManager;
155
-		$this->rootFolder = $rootFolder;
156
-		$this->federatedShareProvider = $federatedShareProvider;
157
-		$this->accountManager = $accountManager;
158
-		$this->eventDispatcher = $eventDispatcher;
159
-		$this->l10n = $l10n;
160
-		$this->defaults = $defaults;
161
-		$this->shareManager = $shareManager;
162
-	}
163
-
164
-	/**
165
-	 * @PublicPage
166
-	 * @NoCSRFRequired
167
-	 *
168
-	 * Show the authentication page
169
-	 * The form has to submit to the authenticate method route
170
-	 */
171
-	public function showAuthenticate(): TemplateResponse {
172
-		$templateParameters = ['share' => $this->share];
173
-
174
-		$event = new GenericEvent(null, $templateParameters);
175
-		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event);
176
-
177
-		$response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
178
-		if ($this->share->getSendPasswordByTalk()) {
179
-			$csp = new ContentSecurityPolicy();
180
-			$csp->addAllowedConnectDomain('*');
181
-			$csp->addAllowedMediaDomain('blob:');
182
-			$response->setContentSecurityPolicy($csp);
183
-		}
184
-
185
-		return $response;
186
-	}
187
-
188
-	/**
189
-	 * The template to show when authentication failed
190
-	 */
191
-	protected function showAuthFailed(): TemplateResponse {
192
-		$templateParameters = ['share' => $this->share, 'wrongpw' => true];
193
-
194
-		$event = new GenericEvent(null, $templateParameters);
195
-		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event);
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
-	protected function verifyPassword(string $password): bool {
209
-		return $this->shareManager->checkPassword($this->share, $password);
210
-	}
211
-
212
-	protected function getPasswordHash(): string {
213
-		return $this->share->getPassword();
214
-	}
215
-
216
-	public function isValidToken(): bool {
217
-		try {
218
-			$this->share = $this->shareManager->getShareByToken($this->getToken());
219
-		} catch (ShareNotFound $e) {
220
-			return false;
221
-		}
222
-
223
-		return true;
224
-	}
225
-
226
-	protected function isPasswordProtected(): bool {
227
-		return $this->share->getPassword() !== null;
228
-	}
229
-
230
-	protected function authSucceeded() {
231
-		// For share this was always set so it is still used in other apps
232
-		$this->session->set('public_link_authenticated', (string)$this->share->getId());
233
-	}
234
-
235
-	protected function authFailed() {
236
-		$this->emitAccessShareHook($this->share, 403, 'Wrong password');
237
-	}
238
-
239
-	/**
240
-	 * throws hooks when a share is attempted to be accessed
241
-	 *
242
-	 * @param \OCP\Share\IShare|string $share the Share instance if available,
243
-	 * otherwise token
244
-	 * @param int $errorCode
245
-	 * @param string $errorMessage
246
-	 * @throws \OC\HintException
247
-	 * @throws \OC\ServerNotAvailableException
248
-	 */
249
-	protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
250
-		$itemType = $itemSource = $uidOwner = '';
251
-		$token = $share;
252
-		$exception = null;
253
-		if ($share instanceof \OCP\Share\IShare) {
254
-			try {
255
-				$token = $share->getToken();
256
-				$uidOwner = $share->getSharedBy();
257
-				$itemType = $share->getNodeType();
258
-				$itemSource = $share->getNodeId();
259
-			} catch (\Exception $e) {
260
-				// we log what we know and pass on the exception afterwards
261
-				$exception = $e;
262
-			}
263
-		}
264
-		\OC_Hook::emit(Share::class, 'share_link_access', [
265
-			'itemType' => $itemType,
266
-			'itemSource' => $itemSource,
267
-			'uidOwner' => $uidOwner,
268
-			'token' => $token,
269
-			'errorCode' => $errorCode,
270
-			'errorMessage' => $errorMessage,
271
-		]);
272
-		if (!is_null($exception)) {
273
-			throw $exception;
274
-		}
275
-	}
276
-
277
-	/**
278
-	 * Validate the permissions of the share
279
-	 *
280
-	 * @param Share\IShare $share
281
-	 * @return bool
282
-	 */
283
-	private function validateShare(\OCP\Share\IShare $share) {
284
-		// If the owner is disabled no access to the linke is granted
285
-		$owner = $this->userManager->get($share->getShareOwner());
286
-		if ($owner === null || !$owner->isEnabled()) {
287
-			return false;
288
-		}
289
-
290
-		// If the initiator of the share is disabled no access is granted
291
-		$initiator = $this->userManager->get($share->getSharedBy());
292
-		if ($initiator === null || !$initiator->isEnabled()) {
293
-			return false;
294
-		}
295
-
296
-		return $share->getNode()->isReadable() && $share->getNode()->isShareable();
297
-	}
298
-
299
-	/**
300
-	 * @PublicPage
301
-	 * @NoCSRFRequired
302
-	 *
303
-	 *
304
-	 * @param string $path
305
-	 * @return TemplateResponse
306
-	 * @throws NotFoundException
307
-	 * @throws \Exception
308
-	 */
309
-	public function showShare($path = ''): TemplateResponse {
310
-		\OC_User::setIncognitoMode(true);
311
-
312
-		// Check whether share exists
313
-		try {
314
-			$share = $this->shareManager->getShareByToken($this->getToken());
315
-		} catch (ShareNotFound $e) {
316
-			$this->emitAccessShareHook($this->getToken(), 404, 'Share not found');
317
-			throw new NotFoundException();
318
-		}
319
-
320
-		if (!$this->validateShare($share)) {
321
-			throw new NotFoundException();
322
-		}
323
-
324
-		$shareNode = $share->getNode();
325
-
326
-		// We can't get the path of a file share
327
-		try {
328
-			if ($shareNode instanceof \OCP\Files\File && $path !== '') {
329
-				$this->emitAccessShareHook($share, 404, 'Share not found');
330
-				throw new NotFoundException();
331
-			}
332
-		} catch (\Exception $e) {
333
-			$this->emitAccessShareHook($share, 404, 'Share not found');
334
-			throw $e;
335
-		}
336
-
337
-		$shareTmpl = [];
338
-		$shareTmpl['owner'] = '';
339
-		$shareTmpl['shareOwner'] = '';
340
-
341
-		$owner = $this->userManager->get($share->getShareOwner());
342
-		if ($owner instanceof IUser) {
343
-			$ownerAccount = $this->accountManager->getAccount($owner);
344
-
345
-			$ownerName = $ownerAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME);
346
-			if ($ownerName->getScope() === IAccountManager::VISIBILITY_PUBLIC) {
347
-				$shareTmpl['owner'] = $owner->getUID();
348
-				$shareTmpl['shareOwner'] = $owner->getDisplayName();
349
-			}
350
-		}
351
-
352
-		$shareTmpl['filename'] = $shareNode->getName();
353
-		$shareTmpl['directory_path'] = $share->getTarget();
354
-		$shareTmpl['note'] = $share->getNote();
355
-		$shareTmpl['mimetype'] = $shareNode->getMimetype();
356
-		$shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($shareNode->getMimetype());
357
-		$shareTmpl['dirToken'] = $this->getToken();
358
-		$shareTmpl['sharingToken'] = $this->getToken();
359
-		$shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
360
-		$shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
361
-		$shareTmpl['dir'] = '';
362
-		$shareTmpl['nonHumanFileSize'] = $shareNode->getSize();
363
-		$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($shareNode->getSize());
364
-		$shareTmpl['hideDownload'] = $share->getHideDownload();
365
-
366
-		$hideFileList = false;
367
-
368
-		if ($shareNode instanceof \OCP\Files\Folder) {
369
-			$shareIsFolder = true;
370
-
371
-			try {
372
-				$folderNode = $shareNode->get($path);
373
-			} catch (\OCP\Files\NotFoundException $e) {
374
-				$this->emitAccessShareHook($share, 404, 'Share not found');
375
-				throw new NotFoundException();
376
-			}
377
-
378
-			$shareTmpl['dir'] = $shareNode->getRelativePath($folderNode->getPath());
379
-
380
-			/*
86
+    /** @var IConfig */
87
+    protected $config;
88
+    /** @var IUserManager */
89
+    protected $userManager;
90
+    /** @var ILogger */
91
+    protected $logger;
92
+    /** @var \OCP\Activity\IManager */
93
+    protected $activityManager;
94
+    /** @var IPreview */
95
+    protected $previewManager;
96
+    /** @var IRootFolder */
97
+    protected $rootFolder;
98
+    /** @var FederatedShareProvider */
99
+    protected $federatedShareProvider;
100
+    /** @var IAccountManager */
101
+    protected $accountManager;
102
+    /** @var EventDispatcherInterface */
103
+    protected $eventDispatcher;
104
+    /** @var IL10N */
105
+    protected $l10n;
106
+    /** @var Defaults */
107
+    protected $defaults;
108
+    /** @var ShareManager */
109
+    protected $shareManager;
110
+
111
+    /** @var Share\IShare */
112
+    protected $share;
113
+
114
+    /**
115
+     * @param string $appName
116
+     * @param IRequest $request
117
+     * @param IConfig $config
118
+     * @param IURLGenerator $urlGenerator
119
+     * @param IUserManager $userManager
120
+     * @param ILogger $logger
121
+     * @param \OCP\Activity\IManager $activityManager
122
+     * @param \OCP\Share\IManager $shareManager
123
+     * @param ISession $session
124
+     * @param IPreview $previewManager
125
+     * @param IRootFolder $rootFolder
126
+     * @param FederatedShareProvider $federatedShareProvider
127
+     * @param IAccountManager $accountManager
128
+     * @param EventDispatcherInterface $eventDispatcher
129
+     * @param IL10N $l10n
130
+     * @param Defaults $defaults
131
+     */
132
+    public function __construct(string $appName,
133
+                                IRequest $request,
134
+                                IConfig $config,
135
+                                IURLGenerator $urlGenerator,
136
+                                IUserManager $userManager,
137
+                                ILogger $logger,
138
+                                \OCP\Activity\IManager $activityManager,
139
+                                ShareManager $shareManager,
140
+                                ISession $session,
141
+                                IPreview $previewManager,
142
+                                IRootFolder $rootFolder,
143
+                                FederatedShareProvider $federatedShareProvider,
144
+                                IAccountManager $accountManager,
145
+                                EventDispatcherInterface $eventDispatcher,
146
+                                IL10N $l10n,
147
+                                Defaults $defaults) {
148
+        parent::__construct($appName, $request, $session, $urlGenerator);
149
+
150
+        $this->config = $config;
151
+        $this->userManager = $userManager;
152
+        $this->logger = $logger;
153
+        $this->activityManager = $activityManager;
154
+        $this->previewManager = $previewManager;
155
+        $this->rootFolder = $rootFolder;
156
+        $this->federatedShareProvider = $federatedShareProvider;
157
+        $this->accountManager = $accountManager;
158
+        $this->eventDispatcher = $eventDispatcher;
159
+        $this->l10n = $l10n;
160
+        $this->defaults = $defaults;
161
+        $this->shareManager = $shareManager;
162
+    }
163
+
164
+    /**
165
+     * @PublicPage
166
+     * @NoCSRFRequired
167
+     *
168
+     * Show the authentication page
169
+     * The form has to submit to the authenticate method route
170
+     */
171
+    public function showAuthenticate(): TemplateResponse {
172
+        $templateParameters = ['share' => $this->share];
173
+
174
+        $event = new GenericEvent(null, $templateParameters);
175
+        $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event);
176
+
177
+        $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
178
+        if ($this->share->getSendPasswordByTalk()) {
179
+            $csp = new ContentSecurityPolicy();
180
+            $csp->addAllowedConnectDomain('*');
181
+            $csp->addAllowedMediaDomain('blob:');
182
+            $response->setContentSecurityPolicy($csp);
183
+        }
184
+
185
+        return $response;
186
+    }
187
+
188
+    /**
189
+     * The template to show when authentication failed
190
+     */
191
+    protected function showAuthFailed(): TemplateResponse {
192
+        $templateParameters = ['share' => $this->share, 'wrongpw' => true];
193
+
194
+        $event = new GenericEvent(null, $templateParameters);
195
+        $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event);
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
+    protected function verifyPassword(string $password): bool {
209
+        return $this->shareManager->checkPassword($this->share, $password);
210
+    }
211
+
212
+    protected function getPasswordHash(): string {
213
+        return $this->share->getPassword();
214
+    }
215
+
216
+    public function isValidToken(): bool {
217
+        try {
218
+            $this->share = $this->shareManager->getShareByToken($this->getToken());
219
+        } catch (ShareNotFound $e) {
220
+            return false;
221
+        }
222
+
223
+        return true;
224
+    }
225
+
226
+    protected function isPasswordProtected(): bool {
227
+        return $this->share->getPassword() !== null;
228
+    }
229
+
230
+    protected function authSucceeded() {
231
+        // For share this was always set so it is still used in other apps
232
+        $this->session->set('public_link_authenticated', (string)$this->share->getId());
233
+    }
234
+
235
+    protected function authFailed() {
236
+        $this->emitAccessShareHook($this->share, 403, 'Wrong password');
237
+    }
238
+
239
+    /**
240
+     * throws hooks when a share is attempted to be accessed
241
+     *
242
+     * @param \OCP\Share\IShare|string $share the Share instance if available,
243
+     * otherwise token
244
+     * @param int $errorCode
245
+     * @param string $errorMessage
246
+     * @throws \OC\HintException
247
+     * @throws \OC\ServerNotAvailableException
248
+     */
249
+    protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
250
+        $itemType = $itemSource = $uidOwner = '';
251
+        $token = $share;
252
+        $exception = null;
253
+        if ($share instanceof \OCP\Share\IShare) {
254
+            try {
255
+                $token = $share->getToken();
256
+                $uidOwner = $share->getSharedBy();
257
+                $itemType = $share->getNodeType();
258
+                $itemSource = $share->getNodeId();
259
+            } catch (\Exception $e) {
260
+                // we log what we know and pass on the exception afterwards
261
+                $exception = $e;
262
+            }
263
+        }
264
+        \OC_Hook::emit(Share::class, 'share_link_access', [
265
+            'itemType' => $itemType,
266
+            'itemSource' => $itemSource,
267
+            'uidOwner' => $uidOwner,
268
+            'token' => $token,
269
+            'errorCode' => $errorCode,
270
+            'errorMessage' => $errorMessage,
271
+        ]);
272
+        if (!is_null($exception)) {
273
+            throw $exception;
274
+        }
275
+    }
276
+
277
+    /**
278
+     * Validate the permissions of the share
279
+     *
280
+     * @param Share\IShare $share
281
+     * @return bool
282
+     */
283
+    private function validateShare(\OCP\Share\IShare $share) {
284
+        // If the owner is disabled no access to the linke is granted
285
+        $owner = $this->userManager->get($share->getShareOwner());
286
+        if ($owner === null || !$owner->isEnabled()) {
287
+            return false;
288
+        }
289
+
290
+        // If the initiator of the share is disabled no access is granted
291
+        $initiator = $this->userManager->get($share->getSharedBy());
292
+        if ($initiator === null || !$initiator->isEnabled()) {
293
+            return false;
294
+        }
295
+
296
+        return $share->getNode()->isReadable() && $share->getNode()->isShareable();
297
+    }
298
+
299
+    /**
300
+     * @PublicPage
301
+     * @NoCSRFRequired
302
+     *
303
+     *
304
+     * @param string $path
305
+     * @return TemplateResponse
306
+     * @throws NotFoundException
307
+     * @throws \Exception
308
+     */
309
+    public function showShare($path = ''): TemplateResponse {
310
+        \OC_User::setIncognitoMode(true);
311
+
312
+        // Check whether share exists
313
+        try {
314
+            $share = $this->shareManager->getShareByToken($this->getToken());
315
+        } catch (ShareNotFound $e) {
316
+            $this->emitAccessShareHook($this->getToken(), 404, 'Share not found');
317
+            throw new NotFoundException();
318
+        }
319
+
320
+        if (!$this->validateShare($share)) {
321
+            throw new NotFoundException();
322
+        }
323
+
324
+        $shareNode = $share->getNode();
325
+
326
+        // We can't get the path of a file share
327
+        try {
328
+            if ($shareNode instanceof \OCP\Files\File && $path !== '') {
329
+                $this->emitAccessShareHook($share, 404, 'Share not found');
330
+                throw new NotFoundException();
331
+            }
332
+        } catch (\Exception $e) {
333
+            $this->emitAccessShareHook($share, 404, 'Share not found');
334
+            throw $e;
335
+        }
336
+
337
+        $shareTmpl = [];
338
+        $shareTmpl['owner'] = '';
339
+        $shareTmpl['shareOwner'] = '';
340
+
341
+        $owner = $this->userManager->get($share->getShareOwner());
342
+        if ($owner instanceof IUser) {
343
+            $ownerAccount = $this->accountManager->getAccount($owner);
344
+
345
+            $ownerName = $ownerAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME);
346
+            if ($ownerName->getScope() === IAccountManager::VISIBILITY_PUBLIC) {
347
+                $shareTmpl['owner'] = $owner->getUID();
348
+                $shareTmpl['shareOwner'] = $owner->getDisplayName();
349
+            }
350
+        }
351
+
352
+        $shareTmpl['filename'] = $shareNode->getName();
353
+        $shareTmpl['directory_path'] = $share->getTarget();
354
+        $shareTmpl['note'] = $share->getNote();
355
+        $shareTmpl['mimetype'] = $shareNode->getMimetype();
356
+        $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($shareNode->getMimetype());
357
+        $shareTmpl['dirToken'] = $this->getToken();
358
+        $shareTmpl['sharingToken'] = $this->getToken();
359
+        $shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
360
+        $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
361
+        $shareTmpl['dir'] = '';
362
+        $shareTmpl['nonHumanFileSize'] = $shareNode->getSize();
363
+        $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($shareNode->getSize());
364
+        $shareTmpl['hideDownload'] = $share->getHideDownload();
365
+
366
+        $hideFileList = false;
367
+
368
+        if ($shareNode instanceof \OCP\Files\Folder) {
369
+            $shareIsFolder = true;
370
+
371
+            try {
372
+                $folderNode = $shareNode->get($path);
373
+            } catch (\OCP\Files\NotFoundException $e) {
374
+                $this->emitAccessShareHook($share, 404, 'Share not found');
375
+                throw new NotFoundException();
376
+            }
377
+
378
+            $shareTmpl['dir'] = $shareNode->getRelativePath($folderNode->getPath());
379
+
380
+            /*
381 381
 			 * The OC_Util methods require a view. This just uses the node API
382 382
 			 */
383
-			$freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
384
-			if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
385
-				$freeSpace = max($freeSpace, 0);
386
-			} else {
387
-				$freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
388
-			}
389
-
390
-			$hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ);
391
-			$maxUploadFilesize = $freeSpace;
392
-
393
-			$folder = new Template('files', 'list', '');
394
-
395
-			$folder->assign('dir', $shareNode->getRelativePath($folderNode->getPath()));
396
-			$folder->assign('dirToken', $this->getToken());
397
-			$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
398
-			$folder->assign('isPublic', true);
399
-			$folder->assign('hideFileList', $hideFileList);
400
-			$folder->assign('publicUploadEnabled', 'no');
401
-			// default to list view
402
-			$folder->assign('showgridview', false);
403
-			$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
404
-			$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
405
-			$folder->assign('freeSpace', $freeSpace);
406
-			$folder->assign('usedSpacePercent', 0);
407
-			$folder->assign('trash', false);
408
-			$shareTmpl['folder'] = $folder->fetchPage();
409
-		} else {
410
-			$shareIsFolder = false;
411
-		}
412
-
413
-		// default to list view
414
-		$shareTmpl['showgridview'] = false;
415
-
416
-		$shareTmpl['hideFileList'] = $hideFileList;
417
-		$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $this->getToken()]);
418
-		$shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $this->getToken()]);
419
-		$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
420
-		$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
421
-		$shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
422
-		$shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
423
-		$shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
424
-		$shareTmpl['previewURL'] = $shareTmpl['downloadURL'];
425
-
426
-		if ($shareTmpl['previewSupported']) {
427
-			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview',
428
-				['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 'token' => $shareTmpl['dirToken']]);
429
-			$ogPreview = $shareTmpl['previewImage'];
430
-
431
-			// We just have direct previews for image files
432
-			if ($shareNode->getMimePart() === 'image') {
433
-				$shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $this->getToken()]);
434
-
435
-				$ogPreview = $shareTmpl['previewURL'];
436
-
437
-				//Whatapp is kind of picky about their size requirements
438
-				if ($this->request->isUserAgent(['/^WhatsApp/'])) {
439
-					$ogPreview = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', [
440
-						'token' => $this->getToken(),
441
-						'x' => 256,
442
-						'y' => 256,
443
-						'a' => true,
444
-					]);
445
-				}
446
-			}
447
-		} else {
448
-			$shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
449
-			$ogPreview = $shareTmpl['previewImage'];
450
-		}
451
-
452
-		// Load files we need
453
-		\OCP\Util::addScript('files', 'semaphore');
454
-		\OCP\Util::addScript('files', 'file-upload');
455
-		\OCP\Util::addStyle('files_sharing', 'publicView');
456
-		\OCP\Util::addScript('files_sharing', 'public');
457
-		\OCP\Util::addScript('files_sharing', 'templates');
458
-		\OCP\Util::addScript('files', 'fileactions');
459
-		\OCP\Util::addScript('files', 'fileactionsmenu');
460
-		\OCP\Util::addScript('files', 'jquery.fileupload');
461
-		\OCP\Util::addScript('files_sharing', 'files_drop');
462
-
463
-		if (isset($shareTmpl['folder'])) {
464
-			// JS required for folders
465
-			\OCP\Util::addStyle('files', 'merged');
466
-			\OCP\Util::addScript('files', 'filesummary');
467
-			\OCP\Util::addScript('files', 'templates');
468
-			\OCP\Util::addScript('files', 'breadcrumb');
469
-			\OCP\Util::addScript('files', 'fileinfomodel');
470
-			\OCP\Util::addScript('files', 'newfilemenu');
471
-			\OCP\Util::addScript('files', 'files');
472
-			\OCP\Util::addScript('files', 'filemultiselectmenu');
473
-			\OCP\Util::addScript('files', 'filelist');
474
-			\OCP\Util::addScript('files', 'keyboardshortcuts');
475
-			\OCP\Util::addScript('files', 'operationprogressbar');
476
-
477
-			// Load Viewer scripts
478
-			if (class_exists(LoadViewer::class)) {
479
-				$this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer());
480
-			}
481
-		}
482
-
483
-		// OpenGraph Support: http://ogp.me/
484
-		\OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]);
485
-		\OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]);
486
-		\OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
487
-		\OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
488
-		\OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
489
-		\OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]);
490
-
491
-		$event = new GenericEvent(null, ['share' => $share]);
492
-		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts', $event);
493
-
494
-		$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
495
-		$csp->addAllowedFrameDomain('\'self\'');
496
-
497
-		$response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl);
498
-		$response->setHeaderTitle($shareTmpl['filename']);
499
-		if ($shareTmpl['shareOwner'] !== '') {
500
-			$response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['shareOwner']]));
501
-		}
502
-
503
-		$isNoneFileDropFolder = $shareIsFolder === false || $share->getPermissions() !== \OCP\Constants::PERMISSION_CREATE;
504
-
505
-		if ($isNoneFileDropFolder && !$share->getHideDownload()) {
506
-			\OCP\Util::addScript('files_sharing', 'public_note');
507
-
508
-			$downloadWhite = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0);
509
-			$downloadAllWhite = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download-white', $shareTmpl['downloadURL'], 0);
510
-			$download = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']);
511
-			$downloadAll = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']);
512
-			$directLink = new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']);
513
-			$externalShare = new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['shareOwner'], $shareTmpl['filename']);
514
-
515
-			$responseComposer = [];
516
-
517
-			if ($shareIsFolder) {
518
-				$responseComposer[] = $downloadAllWhite;
519
-				$responseComposer[] = $downloadAll;
520
-			} else {
521
-				$responseComposer[] = $downloadWhite;
522
-				$responseComposer[] = $download;
523
-			}
524
-			$responseComposer[] = $directLink;
525
-			if ($this->federatedShareProvider->isOutgoingServer2serverShareEnabled()) {
526
-				$responseComposer[] = $externalShare;
527
-			}
528
-
529
-			$response->setHeaderActions($responseComposer);
530
-		}
531
-
532
-		$response->setContentSecurityPolicy($csp);
533
-
534
-		$this->emitAccessShareHook($share);
535
-
536
-		return $response;
537
-	}
538
-
539
-	/**
540
-	 * @PublicPage
541
-	 * @NoCSRFRequired
542
-	 * @NoSameSiteCookieRequired
543
-	 *
544
-	 * @param string $token
545
-	 * @param string $files
546
-	 * @param string $path
547
-	 * @param string $downloadStartSecret
548
-	 * @return void|\OCP\AppFramework\Http\Response
549
-	 * @throws NotFoundException
550
-	 */
551
-	public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
552
-		\OC_User::setIncognitoMode(true);
553
-
554
-		$share = $this->shareManager->getShareByToken($token);
555
-
556
-		if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
557
-			return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
558
-		}
559
-
560
-		$files_list = null;
561
-		if (!is_null($files)) { // download selected files
562
-			$files_list = json_decode($files);
563
-			// in case we get only a single file
564
-			if ($files_list === null) {
565
-				$files_list = [$files];
566
-			}
567
-			// Just in case $files is a single int like '1234'
568
-			if (!is_array($files_list)) {
569
-				$files_list = [$files_list];
570
-			}
571
-		}
572
-
573
-		if (!$this->validateShare($share)) {
574
-			throw new NotFoundException();
575
-		}
576
-
577
-		$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
578
-		$originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
579
-
580
-
581
-		// Single file share
582
-		if ($share->getNode() instanceof \OCP\Files\File) {
583
-			// Single file download
584
-			$this->singleFileDownloaded($share, $share->getNode());
585
-		}
586
-		// Directory share
587
-		else {
588
-			/** @var \OCP\Files\Folder $node */
589
-			$node = $share->getNode();
590
-
591
-			// Try to get the path
592
-			if ($path !== '') {
593
-				try {
594
-					$node = $node->get($path);
595
-				} catch (NotFoundException $e) {
596
-					$this->emitAccessShareHook($share, 404, 'Share not found');
597
-					return new NotFoundResponse();
598
-				}
599
-			}
600
-
601
-			$originalSharePath = $userFolder->getRelativePath($node->getPath());
602
-
603
-			if ($node instanceof \OCP\Files\File) {
604
-				// Single file download
605
-				$this->singleFileDownloaded($share, $share->getNode());
606
-			} else {
607
-				try {
608
-					if (!empty($files_list)) {
609
-						$this->fileListDownloaded($share, $files_list, $node);
610
-					} else {
611
-						// The folder is downloaded
612
-						$this->singleFileDownloaded($share, $share->getNode());
613
-					}
614
-				} catch (NotFoundException $e) {
615
-					return new NotFoundResponse();
616
-				}
617
-			}
618
-		}
619
-
620
-		/* FIXME: We should do this all nicely in OCP */
621
-		OC_Util::tearDownFS();
622
-		OC_Util::setupFS($share->getShareOwner());
623
-
624
-		/**
625
-		 * this sets a cookie to be able to recognize the start of the download
626
-		 * the content must not be longer than 32 characters and must only contain
627
-		 * alphanumeric characters
628
-		 */
629
-		if (!empty($downloadStartSecret)
630
-			&& !isset($downloadStartSecret[32])
631
-			&& preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
632
-
633
-			// FIXME: set on the response once we use an actual app framework response
634
-			setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
635
-		}
636
-
637
-		$this->emitAccessShareHook($share);
638
-
639
-		$server_params = [ 'head' => $this->request->getMethod() === 'HEAD' ];
640
-
641
-		/**
642
-		 * Http range requests support
643
-		 */
644
-		if (isset($_SERVER['HTTP_RANGE'])) {
645
-			$server_params['range'] = $this->request->getHeader('Range');
646
-		}
647
-
648
-		// download selected files
649
-		if (!is_null($files) && $files !== '') {
650
-			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
651
-			// after dispatching the request which results in a "Cannot modify header information" notice.
652
-			OC_Files::get($originalSharePath, $files_list, $server_params);
653
-			exit();
654
-		} else {
655
-			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
656
-			// after dispatching the request which results in a "Cannot modify header information" notice.
657
-			OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
658
-			exit();
659
-		}
660
-	}
661
-
662
-	/**
663
-	 * create activity for every downloaded file
664
-	 *
665
-	 * @param Share\IShare $share
666
-	 * @param array $files_list
667
-	 * @param \OCP\Files\Folder $node
668
-	 * @throws NotFoundException when trying to download a folder or multiple files of a "hide download" share
669
-	 */
670
-	protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
671
-		if ($share->getHideDownload() && count($files_list) > 1) {
672
-			throw new NotFoundException('Downloading more than 1 file');
673
-		}
674
-
675
-		foreach ($files_list as $file) {
676
-			$subNode = $node->get($file);
677
-			$this->singleFileDownloaded($share, $subNode);
678
-		}
679
-	}
680
-
681
-	/**
682
-	 * create activity if a single file was downloaded from a link share
683
-	 *
684
-	 * @param Share\IShare $share
685
-	 * @throws NotFoundException when trying to download a folder of a "hide download" share
686
-	 */
687
-	protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
688
-		if ($share->getHideDownload() && $node instanceof Folder) {
689
-			throw new NotFoundException('Downloading a folder');
690
-		}
691
-
692
-		$fileId = $node->getId();
693
-
694
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
695
-		$userNodeList = $userFolder->getById($fileId);
696
-		$userNode = $userNodeList[0];
697
-		$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
698
-		$userPath = $userFolder->getRelativePath($userNode->getPath());
699
-		$ownerPath = $ownerFolder->getRelativePath($node->getPath());
700
-
701
-		$parameters = [$userPath];
702
-
703
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
704
-			if ($node instanceof \OCP\Files\File) {
705
-				$subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
706
-			} else {
707
-				$subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
708
-			}
709
-			$parameters[] = $share->getSharedWith();
710
-		} else {
711
-			if ($node instanceof \OCP\Files\File) {
712
-				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
713
-			} else {
714
-				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
715
-			}
716
-		}
717
-
718
-		$this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
719
-
720
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
721
-			$parameters[0] = $ownerPath;
722
-			$this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
723
-		}
724
-	}
725
-
726
-	/**
727
-	 * publish activity
728
-	 *
729
-	 * @param string $subject
730
-	 * @param array $parameters
731
-	 * @param string $affectedUser
732
-	 * @param int $fileId
733
-	 * @param string $filePath
734
-	 */
735
-	protected function publishActivity($subject,
736
-										array $parameters,
737
-										$affectedUser,
738
-										$fileId,
739
-										$filePath) {
740
-		$event = $this->activityManager->generateEvent();
741
-		$event->setApp('files_sharing')
742
-			->setType('public_links')
743
-			->setSubject($subject, $parameters)
744
-			->setAffectedUser($affectedUser)
745
-			->setObject('files', $fileId, $filePath);
746
-		$this->activityManager->publish($event);
747
-	}
383
+            $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
384
+            if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
385
+                $freeSpace = max($freeSpace, 0);
386
+            } else {
387
+                $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
388
+            }
389
+
390
+            $hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ);
391
+            $maxUploadFilesize = $freeSpace;
392
+
393
+            $folder = new Template('files', 'list', '');
394
+
395
+            $folder->assign('dir', $shareNode->getRelativePath($folderNode->getPath()));
396
+            $folder->assign('dirToken', $this->getToken());
397
+            $folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
398
+            $folder->assign('isPublic', true);
399
+            $folder->assign('hideFileList', $hideFileList);
400
+            $folder->assign('publicUploadEnabled', 'no');
401
+            // default to list view
402
+            $folder->assign('showgridview', false);
403
+            $folder->assign('uploadMaxFilesize', $maxUploadFilesize);
404
+            $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
405
+            $folder->assign('freeSpace', $freeSpace);
406
+            $folder->assign('usedSpacePercent', 0);
407
+            $folder->assign('trash', false);
408
+            $shareTmpl['folder'] = $folder->fetchPage();
409
+        } else {
410
+            $shareIsFolder = false;
411
+        }
412
+
413
+        // default to list view
414
+        $shareTmpl['showgridview'] = false;
415
+
416
+        $shareTmpl['hideFileList'] = $hideFileList;
417
+        $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $this->getToken()]);
418
+        $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $this->getToken()]);
419
+        $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
420
+        $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
421
+        $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
422
+        $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
423
+        $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
424
+        $shareTmpl['previewURL'] = $shareTmpl['downloadURL'];
425
+
426
+        if ($shareTmpl['previewSupported']) {
427
+            $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview',
428
+                ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 'token' => $shareTmpl['dirToken']]);
429
+            $ogPreview = $shareTmpl['previewImage'];
430
+
431
+            // We just have direct previews for image files
432
+            if ($shareNode->getMimePart() === 'image') {
433
+                $shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $this->getToken()]);
434
+
435
+                $ogPreview = $shareTmpl['previewURL'];
436
+
437
+                //Whatapp is kind of picky about their size requirements
438
+                if ($this->request->isUserAgent(['/^WhatsApp/'])) {
439
+                    $ogPreview = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', [
440
+                        'token' => $this->getToken(),
441
+                        'x' => 256,
442
+                        'y' => 256,
443
+                        'a' => true,
444
+                    ]);
445
+                }
446
+            }
447
+        } else {
448
+            $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
449
+            $ogPreview = $shareTmpl['previewImage'];
450
+        }
451
+
452
+        // Load files we need
453
+        \OCP\Util::addScript('files', 'semaphore');
454
+        \OCP\Util::addScript('files', 'file-upload');
455
+        \OCP\Util::addStyle('files_sharing', 'publicView');
456
+        \OCP\Util::addScript('files_sharing', 'public');
457
+        \OCP\Util::addScript('files_sharing', 'templates');
458
+        \OCP\Util::addScript('files', 'fileactions');
459
+        \OCP\Util::addScript('files', 'fileactionsmenu');
460
+        \OCP\Util::addScript('files', 'jquery.fileupload');
461
+        \OCP\Util::addScript('files_sharing', 'files_drop');
462
+
463
+        if (isset($shareTmpl['folder'])) {
464
+            // JS required for folders
465
+            \OCP\Util::addStyle('files', 'merged');
466
+            \OCP\Util::addScript('files', 'filesummary');
467
+            \OCP\Util::addScript('files', 'templates');
468
+            \OCP\Util::addScript('files', 'breadcrumb');
469
+            \OCP\Util::addScript('files', 'fileinfomodel');
470
+            \OCP\Util::addScript('files', 'newfilemenu');
471
+            \OCP\Util::addScript('files', 'files');
472
+            \OCP\Util::addScript('files', 'filemultiselectmenu');
473
+            \OCP\Util::addScript('files', 'filelist');
474
+            \OCP\Util::addScript('files', 'keyboardshortcuts');
475
+            \OCP\Util::addScript('files', 'operationprogressbar');
476
+
477
+            // Load Viewer scripts
478
+            if (class_exists(LoadViewer::class)) {
479
+                $this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer());
480
+            }
481
+        }
482
+
483
+        // OpenGraph Support: http://ogp.me/
484
+        \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]);
485
+        \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]);
486
+        \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
487
+        \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
488
+        \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
489
+        \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]);
490
+
491
+        $event = new GenericEvent(null, ['share' => $share]);
492
+        $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts', $event);
493
+
494
+        $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
495
+        $csp->addAllowedFrameDomain('\'self\'');
496
+
497
+        $response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl);
498
+        $response->setHeaderTitle($shareTmpl['filename']);
499
+        if ($shareTmpl['shareOwner'] !== '') {
500
+            $response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['shareOwner']]));
501
+        }
502
+
503
+        $isNoneFileDropFolder = $shareIsFolder === false || $share->getPermissions() !== \OCP\Constants::PERMISSION_CREATE;
504
+
505
+        if ($isNoneFileDropFolder && !$share->getHideDownload()) {
506
+            \OCP\Util::addScript('files_sharing', 'public_note');
507
+
508
+            $downloadWhite = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0);
509
+            $downloadAllWhite = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download-white', $shareTmpl['downloadURL'], 0);
510
+            $download = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']);
511
+            $downloadAll = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']);
512
+            $directLink = new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']);
513
+            $externalShare = new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['shareOwner'], $shareTmpl['filename']);
514
+
515
+            $responseComposer = [];
516
+
517
+            if ($shareIsFolder) {
518
+                $responseComposer[] = $downloadAllWhite;
519
+                $responseComposer[] = $downloadAll;
520
+            } else {
521
+                $responseComposer[] = $downloadWhite;
522
+                $responseComposer[] = $download;
523
+            }
524
+            $responseComposer[] = $directLink;
525
+            if ($this->federatedShareProvider->isOutgoingServer2serverShareEnabled()) {
526
+                $responseComposer[] = $externalShare;
527
+            }
528
+
529
+            $response->setHeaderActions($responseComposer);
530
+        }
531
+
532
+        $response->setContentSecurityPolicy($csp);
533
+
534
+        $this->emitAccessShareHook($share);
535
+
536
+        return $response;
537
+    }
538
+
539
+    /**
540
+     * @PublicPage
541
+     * @NoCSRFRequired
542
+     * @NoSameSiteCookieRequired
543
+     *
544
+     * @param string $token
545
+     * @param string $files
546
+     * @param string $path
547
+     * @param string $downloadStartSecret
548
+     * @return void|\OCP\AppFramework\Http\Response
549
+     * @throws NotFoundException
550
+     */
551
+    public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
552
+        \OC_User::setIncognitoMode(true);
553
+
554
+        $share = $this->shareManager->getShareByToken($token);
555
+
556
+        if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
557
+            return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
558
+        }
559
+
560
+        $files_list = null;
561
+        if (!is_null($files)) { // download selected files
562
+            $files_list = json_decode($files);
563
+            // in case we get only a single file
564
+            if ($files_list === null) {
565
+                $files_list = [$files];
566
+            }
567
+            // Just in case $files is a single int like '1234'
568
+            if (!is_array($files_list)) {
569
+                $files_list = [$files_list];
570
+            }
571
+        }
572
+
573
+        if (!$this->validateShare($share)) {
574
+            throw new NotFoundException();
575
+        }
576
+
577
+        $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
578
+        $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
579
+
580
+
581
+        // Single file share
582
+        if ($share->getNode() instanceof \OCP\Files\File) {
583
+            // Single file download
584
+            $this->singleFileDownloaded($share, $share->getNode());
585
+        }
586
+        // Directory share
587
+        else {
588
+            /** @var \OCP\Files\Folder $node */
589
+            $node = $share->getNode();
590
+
591
+            // Try to get the path
592
+            if ($path !== '') {
593
+                try {
594
+                    $node = $node->get($path);
595
+                } catch (NotFoundException $e) {
596
+                    $this->emitAccessShareHook($share, 404, 'Share not found');
597
+                    return new NotFoundResponse();
598
+                }
599
+            }
600
+
601
+            $originalSharePath = $userFolder->getRelativePath($node->getPath());
602
+
603
+            if ($node instanceof \OCP\Files\File) {
604
+                // Single file download
605
+                $this->singleFileDownloaded($share, $share->getNode());
606
+            } else {
607
+                try {
608
+                    if (!empty($files_list)) {
609
+                        $this->fileListDownloaded($share, $files_list, $node);
610
+                    } else {
611
+                        // The folder is downloaded
612
+                        $this->singleFileDownloaded($share, $share->getNode());
613
+                    }
614
+                } catch (NotFoundException $e) {
615
+                    return new NotFoundResponse();
616
+                }
617
+            }
618
+        }
619
+
620
+        /* FIXME: We should do this all nicely in OCP */
621
+        OC_Util::tearDownFS();
622
+        OC_Util::setupFS($share->getShareOwner());
623
+
624
+        /**
625
+         * this sets a cookie to be able to recognize the start of the download
626
+         * the content must not be longer than 32 characters and must only contain
627
+         * alphanumeric characters
628
+         */
629
+        if (!empty($downloadStartSecret)
630
+            && !isset($downloadStartSecret[32])
631
+            && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
632
+
633
+            // FIXME: set on the response once we use an actual app framework response
634
+            setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
635
+        }
636
+
637
+        $this->emitAccessShareHook($share);
638
+
639
+        $server_params = [ 'head' => $this->request->getMethod() === 'HEAD' ];
640
+
641
+        /**
642
+         * Http range requests support
643
+         */
644
+        if (isset($_SERVER['HTTP_RANGE'])) {
645
+            $server_params['range'] = $this->request->getHeader('Range');
646
+        }
647
+
648
+        // download selected files
649
+        if (!is_null($files) && $files !== '') {
650
+            // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
651
+            // after dispatching the request which results in a "Cannot modify header information" notice.
652
+            OC_Files::get($originalSharePath, $files_list, $server_params);
653
+            exit();
654
+        } else {
655
+            // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
656
+            // after dispatching the request which results in a "Cannot modify header information" notice.
657
+            OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
658
+            exit();
659
+        }
660
+    }
661
+
662
+    /**
663
+     * create activity for every downloaded file
664
+     *
665
+     * @param Share\IShare $share
666
+     * @param array $files_list
667
+     * @param \OCP\Files\Folder $node
668
+     * @throws NotFoundException when trying to download a folder or multiple files of a "hide download" share
669
+     */
670
+    protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
671
+        if ($share->getHideDownload() && count($files_list) > 1) {
672
+            throw new NotFoundException('Downloading more than 1 file');
673
+        }
674
+
675
+        foreach ($files_list as $file) {
676
+            $subNode = $node->get($file);
677
+            $this->singleFileDownloaded($share, $subNode);
678
+        }
679
+    }
680
+
681
+    /**
682
+     * create activity if a single file was downloaded from a link share
683
+     *
684
+     * @param Share\IShare $share
685
+     * @throws NotFoundException when trying to download a folder of a "hide download" share
686
+     */
687
+    protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
688
+        if ($share->getHideDownload() && $node instanceof Folder) {
689
+            throw new NotFoundException('Downloading a folder');
690
+        }
691
+
692
+        $fileId = $node->getId();
693
+
694
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
695
+        $userNodeList = $userFolder->getById($fileId);
696
+        $userNode = $userNodeList[0];
697
+        $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
698
+        $userPath = $userFolder->getRelativePath($userNode->getPath());
699
+        $ownerPath = $ownerFolder->getRelativePath($node->getPath());
700
+
701
+        $parameters = [$userPath];
702
+
703
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
704
+            if ($node instanceof \OCP\Files\File) {
705
+                $subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
706
+            } else {
707
+                $subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
708
+            }
709
+            $parameters[] = $share->getSharedWith();
710
+        } else {
711
+            if ($node instanceof \OCP\Files\File) {
712
+                $subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
713
+            } else {
714
+                $subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
715
+            }
716
+        }
717
+
718
+        $this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
719
+
720
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
721
+            $parameters[0] = $ownerPath;
722
+            $this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
723
+        }
724
+    }
725
+
726
+    /**
727
+     * publish activity
728
+     *
729
+     * @param string $subject
730
+     * @param array $parameters
731
+     * @param string $affectedUser
732
+     * @param int $fileId
733
+     * @param string $filePath
734
+     */
735
+    protected function publishActivity($subject,
736
+                                        array $parameters,
737
+                                        $affectedUser,
738
+                                        $fileId,
739
+                                        $filePath) {
740
+        $event = $this->activityManager->generateEvent();
741
+        $event->setApp('files_sharing')
742
+            ->setType('public_links')
743
+            ->setSubject($subject, $parameters)
744
+            ->setAffectedUser($affectedUser)
745
+            ->setObject('files', $fileId, $filePath);
746
+        $this->activityManager->publish($event);
747
+    }
748 748
 }
Please login to merge, or discard this patch.