aboutsummaryrefslogtreecommitdiffstats
path: root/core/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'core/Controller')
-rw-r--r--core/Controller/AppPasswordController.php2
-rw-r--r--core/Controller/AvatarController.php4
-rw-r--r--core/Controller/CSRFTokenController.php2
-rw-r--r--core/Controller/ClientFlowLoginController.php9
-rw-r--r--core/Controller/ClientFlowLoginV2Controller.php4
-rw-r--r--core/Controller/ContactsMenuController.php1
-rw-r--r--core/Controller/GuestAvatarController.php1
-rw-r--r--core/Controller/LoginController.php4
-rw-r--r--core/Controller/LostController.php4
-rw-r--r--core/Controller/NavigationController.php1
-rw-r--r--core/Controller/OCJSController.php1
-rw-r--r--core/Controller/OCSController.php1
-rw-r--r--core/Controller/PreviewController.php7
-rw-r--r--core/Controller/TaskProcessingApiController.php86
-rw-r--r--core/Controller/TwoFactorChallengeController.php5
-rw-r--r--core/Controller/WalledGardenController.php1
-rw-r--r--core/Controller/WhatsNewController.php1
17 files changed, 100 insertions, 34 deletions
diff --git a/core/Controller/AppPasswordController.php b/core/Controller/AppPasswordController.php
index 41a45926ba7..e5edc165bf5 100644
--- a/core/Controller/AppPasswordController.php
+++ b/core/Controller/AppPasswordController.php
@@ -77,7 +77,7 @@ class AppPasswordController extends OCSController {
$password = null;
}
- $userAgent = $this->request->getHeader('USER_AGENT');
+ $userAgent = $this->request->getHeader('user-agent');
$token = $this->random->generate(72, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
diff --git a/core/Controller/AvatarController.php b/core/Controller/AvatarController.php
index 4e7a2f8714a..b577b2fd460 100644
--- a/core/Controller/AvatarController.php
+++ b/core/Controller/AvatarController.php
@@ -193,8 +193,8 @@ class AvatarController extends Controller {
}
} elseif (!is_null($files)) {
if (
- $files['error'][0] === 0 &&
- is_uploaded_file($files['tmp_name'][0])
+ $files['error'][0] === 0
+ && is_uploaded_file($files['tmp_name'][0])
) {
if ($files['size'][0] > 20 * 1024 * 1024) {
return new JSONResponse(
diff --git a/core/Controller/CSRFTokenController.php b/core/Controller/CSRFTokenController.php
index 4fdd669e144..edf7c26e94c 100644
--- a/core/Controller/CSRFTokenController.php
+++ b/core/Controller/CSRFTokenController.php
@@ -34,6 +34,8 @@ class CSRFTokenController extends Controller {
*
* 200: CSRF token returned
* 403: Strict cookie check failed
+ *
+ * @NoTwoFactorRequired
*/
#[PublicPage]
#[NoCSRFRequired]
diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php
index affb60f2b2e..4464af890c4 100644
--- a/core/Controller/ClientFlowLoginController.php
+++ b/core/Controller/ClientFlowLoginController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -17,6 +18,7 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\OpenAPI;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\ContentSecurityPolicy;
@@ -64,7 +66,7 @@ class ClientFlowLoginController extends Controller {
}
private function getClientName(): string {
- $userAgent = $this->request->getHeader('USER_AGENT');
+ $userAgent = $this->request->getHeader('user-agent');
return $userAgent !== '' ? $userAgent : 'unknown';
}
@@ -108,8 +110,8 @@ class ClientFlowLoginController extends Controller {
$this->appName,
'error',
[
- 'errors' =>
- [
+ 'errors'
+ => [
[
'error' => 'Access Forbidden',
'hint' => 'Invalid request',
@@ -214,6 +216,7 @@ class ClientFlowLoginController extends Controller {
#[NoAdminRequired]
#[UseSession]
+ #[PasswordConfirmationRequired(strict: false)]
#[FrontpageRoute(verb: 'POST', url: '/login/flow')]
public function generateAppPassword(
string $stateToken,
diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php
index e21a0cb250d..8c0c1e8179d 100644
--- a/core/Controller/ClientFlowLoginV2Controller.php
+++ b/core/Controller/ClientFlowLoginV2Controller.php
@@ -19,6 +19,7 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\OpenAPI;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\JSONResponse;
@@ -228,6 +229,7 @@ class ClientFlowLoginV2Controller extends Controller {
#[NoAdminRequired]
#[UseSession]
+ #[PasswordConfirmationRequired(strict: false)]
#[FrontpageRoute(verb: 'POST', url: '/login/v2/grant')]
public function generateAppPassword(?string $stateToken): Response {
if ($stateToken === null) {
@@ -291,7 +293,7 @@ class ClientFlowLoginV2Controller extends Controller {
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
public function init(): JSONResponse {
// Get client user agent
- $userAgent = $this->request->getHeader('USER_AGENT');
+ $userAgent = $this->request->getHeader('user-agent');
$tokens = $this->loginFlowV2Service->createTokens($userAgent);
diff --git a/core/Controller/ContactsMenuController.php b/core/Controller/ContactsMenuController.php
index f4ded1ed42b..d90ee8a1c61 100644
--- a/core/Controller/ContactsMenuController.php
+++ b/core/Controller/ContactsMenuController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/core/Controller/GuestAvatarController.php b/core/Controller/GuestAvatarController.php
index 818b25a0c80..711158e0708 100644
--- a/core/Controller/GuestAvatarController.php
+++ b/core/Controller/GuestAvatarController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php
index 7e8afd9f083..5a21d27898f 100644
--- a/core/Controller/LoginController.php
+++ b/core/Controller/LoginController.php
@@ -93,8 +93,8 @@ class LoginController extends Controller {
$this->session->close();
if (
- $this->request->getServerProtocol() === 'https' &&
- !$this->request->isUserAgent([Request::USER_AGENT_CHROME, Request::USER_AGENT_ANDROID_MOBILE_CHROME])
+ $this->request->getServerProtocol() === 'https'
+ && !$this->request->isUserAgent([Request::USER_AGENT_CHROME, Request::USER_AGENT_ANDROID_MOBILE_CHROME])
) {
$response->addHeader('Clear-Site-Data', '"cache", "storage"');
}
diff --git a/core/Controller/LostController.php b/core/Controller/LostController.php
index f940a3cfeee..d956f3427f2 100644
--- a/core/Controller/LostController.php
+++ b/core/Controller/LostController.php
@@ -64,7 +64,7 @@ class LostController extends Controller {
private Defaults $defaults,
private IL10N $l10n,
private IConfig $config,
- protected string $from,
+ protected string $defaultMailAddress,
private IManager $encryptionManager,
private IMailer $mailer,
private LoggerInterface $logger,
@@ -281,7 +281,7 @@ class LostController extends Controller {
try {
$message = $this->mailer->createMessage();
$message->setTo([$email => $user->getDisplayName()]);
- $message->setFrom([$this->from => $this->defaults->getName()]);
+ $message->setFrom([$this->defaultMailAddress => $this->defaults->getName()]);
$message->useTemplate($emailTemplate);
$this->mailer->send($message);
} catch (Exception $e) {
diff --git a/core/Controller/NavigationController.php b/core/Controller/NavigationController.php
index 5fc929b4eb4..017061ef979 100644
--- a/core/Controller/NavigationController.php
+++ b/core/Controller/NavigationController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/core/Controller/OCJSController.php b/core/Controller/OCJSController.php
index 176558b013d..ea372b43b2e 100644
--- a/core/Controller/OCJSController.php
+++ b/core/Controller/OCJSController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/core/Controller/OCSController.php b/core/Controller/OCSController.php
index b05ddd0e298..fb0280479c4 100644
--- a/core/Controller/OCSController.php
+++ b/core/Controller/OCSController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/core/Controller/PreviewController.php b/core/Controller/PreviewController.php
index ea90be31078..aac49c06d57 100644
--- a/core/Controller/PreviewController.php
+++ b/core/Controller/PreviewController.php
@@ -152,15 +152,12 @@ class PreviewController extends Controller {
// Is this header is set it means our UI is doing a preview for no-download shares
// we check a header so we at least prevent people from using the link directly (obfuscation)
- $isNextcloudPreview = $this->request->getHeader('X-NC-Preview') === 'true';
+ $isNextcloudPreview = $this->request->getHeader('x-nc-preview') === 'true';
$storage = $node->getStorage();
if ($isNextcloudPreview === false && $storage->instanceOfStorage(ISharedStorage::class)) {
/** @var ISharedStorage $storage */
$share = $storage->getShare();
- $attributes = $share->getAttributes();
- // No "allow preview" header set, so we must check if
- // the share has not explicitly disabled download permissions
- if ($attributes?->getAttribute('permissions', 'download') === false) {
+ if (!$share->canSeeContent()) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
}
diff --git a/core/Controller/TaskProcessingApiController.php b/core/Controller/TaskProcessingApiController.php
index cf62b4f6b6b..90a0e9ba14a 100644
--- a/core/Controller/TaskProcessingApiController.php
+++ b/core/Controller/TaskProcessingApiController.php
@@ -20,12 +20,12 @@ use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\Attribute\UserRateLimit;
-use OCP\AppFramework\Http\DataDownloadResponse;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\StreamResponse;
use OCP\AppFramework\OCSController;
use OCP\Files\File;
-use OCP\Files\GenericFileException;
use OCP\Files\IAppData;
+use OCP\Files\IMimeTypeDetector;
use OCP\Files\IRootFolder;
use OCP\Files\NotPermittedException;
use OCP\IL10N;
@@ -56,6 +56,7 @@ class TaskProcessingApiController extends OCSController {
private ?string $userId,
private IRootFolder $rootFolder,
private IAppData $appData,
+ private IMimeTypeDetector $mimeTypeDetector,
) {
parent::__construct($appName, $request);
}
@@ -302,7 +303,7 @@ class TaskProcessingApiController extends OCSController {
*
* @param int $taskId The id of the task
* @param int $fileId The file id of the file to retrieve
- * @return DataDownloadResponse<Http::STATUS_OK, string, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
+ * @return StreamResponse<Http::STATUS_OK, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*
* 200: File content returned
* 404: Task or file not found
@@ -310,12 +311,14 @@ class TaskProcessingApiController extends OCSController {
#[NoAdminRequired]
#[NoCSRFRequired]
#[ApiRoute(verb: 'GET', url: '/tasks/{taskId}/file/{fileId}', root: '/taskprocessing')]
- public function getFileContents(int $taskId, int $fileId): DataDownloadResponse|DataResponse {
+ public function getFileContents(int $taskId, int $fileId): StreamResponse|DataResponse {
try {
$task = $this->taskProcessingManager->getUserTask($taskId, $this->userId);
return $this->getFileContentsInternal($task, $fileId);
} catch (NotFoundException) {
return new DataResponse(['message' => $this->l->t('Not found')], Http::STATUS_NOT_FOUND);
+ } catch (LockedException) {
+ return new DataResponse(['message' => $this->l->t('Node is locked')], Http::STATUS_INTERNAL_SERVER_ERROR);
} catch (Exception) {
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR);
}
@@ -326,19 +329,21 @@ class TaskProcessingApiController extends OCSController {
*
* @param int $taskId The id of the task
* @param int $fileId The file id of the file to retrieve
- * @return DataDownloadResponse<Http::STATUS_OK, string, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
+ * @return StreamResponse<Http::STATUS_OK, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*
* 200: File content returned
* 404: Task or file not found
*/
#[ExAppRequired]
#[ApiRoute(verb: 'GET', url: '/tasks_provider/{taskId}/file/{fileId}', root: '/taskprocessing')]
- public function getFileContentsExApp(int $taskId, int $fileId): DataDownloadResponse|DataResponse {
+ public function getFileContentsExApp(int $taskId, int $fileId): StreamResponse|DataResponse {
try {
$task = $this->taskProcessingManager->getTask($taskId);
return $this->getFileContentsInternal($task, $fileId);
} catch (NotFoundException) {
return new DataResponse(['message' => $this->l->t('Not found')], Http::STATUS_NOT_FOUND);
+ } catch (LockedException) {
+ return new DataResponse(['message' => $this->l->t('Node is locked')], Http::STATUS_INTERNAL_SERVER_ERROR);
} catch (Exception) {
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR);
}
@@ -381,12 +386,11 @@ class TaskProcessingApiController extends OCSController {
/**
* @throws NotPermittedException
* @throws NotFoundException
- * @throws GenericFileException
* @throws LockedException
*
- * @return DataDownloadResponse<Http::STATUS_OK, string, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
+ * @return StreamResponse<Http::STATUS_OK, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*/
- private function getFileContentsInternal(Task $task, int $fileId): DataDownloadResponse|DataResponse {
+ private function getFileContentsInternal(Task $task, int $fileId): StreamResponse|DataResponse {
$ids = $this->extractFileIdsFromTask($task);
if (!in_array($fileId, $ids)) {
return new DataResponse(['message' => $this->l->t('Not found')], Http::STATUS_NOT_FOUND);
@@ -403,7 +407,25 @@ class TaskProcessingApiController extends OCSController {
} elseif (!$node instanceof File) {
throw new NotFoundException('Node is not a file');
}
- return new DataDownloadResponse($node->getContent(), $node->getName(), $node->getMimeType());
+
+ $contentType = $node->getMimeType();
+ if (function_exists('mime_content_type')) {
+ $mimeType = mime_content_type($node->fopen('rb'));
+ if ($mimeType !== false) {
+ $mimeType = $this->mimeTypeDetector->getSecureMimeType($mimeType);
+ if ($mimeType !== 'application/octet-stream') {
+ $contentType = $mimeType;
+ }
+ }
+ }
+
+ $response = new StreamResponse($node->fopen('rb'));
+ $response->addHeader(
+ 'Content-Disposition',
+ 'attachment; filename="' . rawurldecode($node->getName()) . '"'
+ );
+ $response->addHeader('Content-Type', $contentType);
+ return $response;
}
/**
@@ -553,23 +575,51 @@ class TaskProcessingApiController extends OCSController {
#[ApiRoute(verb: 'GET', url: '/tasks_provider/next', root: '/taskprocessing')]
public function getNextScheduledTask(array $providerIds, array $taskTypeIds): DataResponse {
try {
+ $providerIdsBasedOnTaskTypesWithNull = array_unique(array_map(function ($taskTypeId) {
+ try {
+ return $this->taskProcessingManager->getPreferredProvider($taskTypeId)->getId();
+ } catch (Exception) {
+ return null;
+ }
+ }, $taskTypeIds));
+
+ $providerIdsBasedOnTaskTypes = array_filter($providerIdsBasedOnTaskTypesWithNull, fn ($providerId) => $providerId !== null);
+
// restrict $providerIds to providers that are configured as preferred for the passed task types
- $providerIds = array_values(array_intersect(array_unique(array_map(fn ($taskTypeId) => $this->taskProcessingManager->getPreferredProvider($taskTypeId)->getId(), $taskTypeIds)), $providerIds));
+ $possibleProviderIds = array_values(array_intersect($providerIdsBasedOnTaskTypes, $providerIds));
+
// restrict $taskTypeIds to task types that can actually be run by one of the now restricted providers
- $taskTypeIds = array_values(array_filter($taskTypeIds, fn ($taskTypeId) => in_array($this->taskProcessingManager->getPreferredProvider($taskTypeId)->getId(), $providerIds, true)));
- if (count($providerIds) === 0 || count($taskTypeIds) === 0) {
+ $possibleTaskTypeIds = array_values(array_filter($taskTypeIds, function ($taskTypeId) use ($possibleProviderIds) {
+ try {
+ $providerForTaskType = $this->taskProcessingManager->getPreferredProvider($taskTypeId)->getId();
+ } catch (Exception) {
+ // no provider found for task type
+ return false;
+ }
+ return in_array($providerForTaskType, $possibleProviderIds, true);
+ }));
+
+ if (count($possibleProviderIds) === 0 || count($possibleTaskTypeIds) === 0) {
throw new NotFoundException();
}
$taskIdsToIgnore = [];
while (true) {
- $task = $this->taskProcessingManager->getNextScheduledTask($taskTypeIds, $taskIdsToIgnore);
- $provider = $this->taskProcessingManager->getPreferredProvider($task->getTaskTypeId());
- if (in_array($provider->getId(), $providerIds, true)) {
- if ($this->taskProcessingManager->lockTask($task)) {
- break;
+ // Until we find a task whose task type is set to be provided by the providers requested with this request
+ // Or no scheduled task is found anymore (given the taskIds to ignore)
+ $task = $this->taskProcessingManager->getNextScheduledTask($possibleTaskTypeIds, $taskIdsToIgnore);
+ try {
+ $provider = $this->taskProcessingManager->getPreferredProvider($task->getTaskTypeId());
+ if (in_array($provider->getId(), $possibleProviderIds, true)) {
+ if ($this->taskProcessingManager->lockTask($task)) {
+ break;
+ }
}
+ } catch (Exception) {
+ // There is no provider set for the task type of this task
+ // proceed to ignore this task
}
+
$taskIdsToIgnore[] = (int)$task->getId();
}
diff --git a/core/Controller/TwoFactorChallengeController.php b/core/Controller/TwoFactorChallengeController.php
index ef0f420fc82..4791139bb12 100644
--- a/core/Controller/TwoFactorChallengeController.php
+++ b/core/Controller/TwoFactorChallengeController.php
@@ -25,6 +25,7 @@ use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUserSession;
+use OCP\Util;
use Psr\Log\LoggerInterface;
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
@@ -89,6 +90,7 @@ class TwoFactorChallengeController extends Controller {
'logout_url' => $this->getLogoutUrl(),
'hasSetupProviders' => !empty($setupProviders),
];
+ Util::addScript('core', 'twofactor-request-token');
return new StandaloneTemplateResponse($this->appName, 'twofactorselectchallenge', $data, 'guest');
}
@@ -141,6 +143,7 @@ class TwoFactorChallengeController extends Controller {
if ($provider instanceof IProvidesCustomCSP) {
$response->setContentSecurityPolicy($provider->getCSP());
}
+ Util::addScript('core', 'twofactor-request-token');
return $response;
}
@@ -204,6 +207,7 @@ class TwoFactorChallengeController extends Controller {
'redirect_url' => $redirect_url,
];
+ Util::addScript('core', 'twofactor-request-token');
return new StandaloneTemplateResponse($this->appName, 'twofactorsetupselection', $data, 'guest');
}
@@ -235,6 +239,7 @@ class TwoFactorChallengeController extends Controller {
'template' => $tmpl->fetchPage(),
];
$response = new StandaloneTemplateResponse($this->appName, 'twofactorsetupchallenge', $data, 'guest');
+ Util::addScript('core', 'twofactor-request-token');
return $response;
}
diff --git a/core/Controller/WalledGardenController.php b/core/Controller/WalledGardenController.php
index b55e90675a1..d0bc0665534 100644
--- a/core/Controller/WalledGardenController.php
+++ b/core/Controller/WalledGardenController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/core/Controller/WhatsNewController.php b/core/Controller/WhatsNewController.php
index b3bb7becbac..af8c3d4853b 100644
--- a/core/Controller/WhatsNewController.php
+++ b/core/Controller/WhatsNewController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later