diff options
Diffstat (limited to 'lib/public/AppFramework')
91 files changed, 2550 insertions, 1687 deletions
diff --git a/lib/public/AppFramework/ApiController.php b/lib/public/AppFramework/ApiController.php index 83dfaf93bc6..729582c8505 100644 --- a/lib/public/AppFramework/ApiController.php +++ b/lib/public/AppFramework/ApiController.php @@ -1,28 +1,15 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\Response; use OCP\IRequest; @@ -40,20 +27,20 @@ abstract class ApiController extends Controller { * @param string $appName the name of the app * @param IRequest $request an instance of the request * @param string $corsMethods comma separated string of HTTP verbs which - * should be allowed for websites or webapps when calling your API, defaults to - * 'PUT, POST, GET, DELETE, PATCH' + * should be allowed for websites or webapps when calling your API, defaults to + * 'PUT, POST, GET, DELETE, PATCH' * @param string $corsAllowedHeaders comma separated string of HTTP headers - * which should be allowed for websites or webapps when calling your API, - * defaults to 'Authorization, Content-Type, Accept' + * which should be allowed for websites or webapps when calling your API, + * defaults to 'Authorization, Content-Type, Accept' * @param int $corsMaxAge number in seconds how long a preflighted OPTIONS - * request should be cached, defaults to 1728000 seconds + * request should be cached, defaults to 1728000 seconds * @since 7.0.0 */ public function __construct($appName, - IRequest $request, - $corsMethods = 'PUT, POST, GET, DELETE, PATCH', - $corsAllowedHeaders = 'Authorization, Content-Type, Accept', - $corsMaxAge = 1728000) { + IRequest $request, + $corsMethods = 'PUT, POST, GET, DELETE, PATCH', + $corsAllowedHeaders = 'Authorization, Content-Type, Accept', + $corsMaxAge = 1728000) { parent::__construct($appName, $request); $this->corsMethods = $corsMethods; $this->corsAllowedHeaders = $corsAllowedHeaders; @@ -65,15 +52,14 @@ abstract class ApiController extends Controller { * This method implements a preflighted cors response for you that you can * link to for the options request * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage * @since 7.0.0 */ + #[NoCSRFRequired] + #[PublicPage] + #[NoAdminRequired] public function preflightedCors() { - if (isset($this->request->server['HTTP_ORIGIN'])) { - $origin = $this->request->server['HTTP_ORIGIN']; - } else { + $origin = $this->request->getHeader('origin'); + if ($origin === '') { $origin = '*'; } diff --git a/lib/public/AppFramework/App.php b/lib/public/AppFramework/App.php index 4d6e9177b78..c00fde47418 100644 --- a/lib/public/AppFramework/App.php +++ b/lib/public/AppFramework/App.php @@ -3,41 +3,17 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; -use OC\AppFramework\Routing\RouteConfig; -use OC\Route\Router; +use OC\AppFramework\Utility\SimpleContainer; use OC\ServerContainer; -use OCP\Route\IRouter; +use OCP\IConfig; +use OCP\Server; +use Psr\Log\LoggerInterface; /** * Class App @@ -56,7 +32,7 @@ class App { * some_app_id -> OCA\SomeAppId * @param string $appId the app id * @param string $topNamespace the namespace which should be prepended to - * the transformed app id, defaults to OCA\ + * the transformed app id, defaults to OCA\ * @return string the starting namespace for the app * @since 8.0.0 */ @@ -71,8 +47,8 @@ class App { * @since 6.0.0 */ public function __construct(string $appName, array $urlParams = []) { - $runIsSetupDirectly = \OC::$server->getConfig()->getSystemValueBool('debug') - && (PHP_VERSION_ID < 70400 || (PHP_VERSION_ID >= 70400 && !ini_get('zend.exception_ignore_args'))); + $runIsSetupDirectly = Server::get(IConfig::class)->getSystemValueBool('debug') + && !ini_get('zend.exception_ignore_args'); if ($runIsSetupDirectly) { $applicationClassName = get_class($this); @@ -82,24 +58,32 @@ class App { $classNameParts = explode('\\', trim($applicationClassName, '\\')); foreach ($e->getTrace() as $step) { - if (isset($step['class'], $step['function'], $step['args'][0]) && - $step['class'] === ServerContainer::class && - $step['function'] === 'query' && - $step['args'][0] === $applicationClassName) { + if (isset($step['class'], $step['function'], $step['args'][0]) + && $step['class'] === ServerContainer::class + && $step['function'] === 'query' + && $step['args'][0] === $applicationClassName) { + $setUpViaQuery = true; + break; + } elseif (isset($step['class'], $step['function'], $step['args'][0]) + && $step['class'] === ServerContainer::class + && $step['function'] === 'getAppContainer' + && $step['args'][1] === $classNameParts[1]) { $setUpViaQuery = true; break; - } elseif (isset($step['class'], $step['function'], $step['args'][0]) && - $step['class'] === ServerContainer::class && - $step['function'] === 'getAppContainer' && - $step['args'][1] === $classNameParts[1]) { + } elseif (isset($step['class'], $step['function'], $step['args'][0]) + && $step['class'] === SimpleContainer::class + && preg_match('/{closure:OC\\\\AppFramework\\\\Utility\\\\SimpleContainer::buildClass\\(\\):\\d+}/', $step['function']) + && $step['args'][0] === $this) { + /* We are setup through a lazy ghost, fine */ $setUpViaQuery = true; break; } } if (!$setUpViaQuery && $applicationClassName !== \OCP\AppFramework\App::class) { - \OC::$server->getLogger()->logException($e, [ + Server::get(LoggerInterface::class)->error($e->getMessage(), [ 'app' => $appName, + 'exception' => $e, ]); } } @@ -120,35 +104,6 @@ class App { } /** - * This function is to be called to create single routes and restful routes based on the given $routes array. - * - * Example code in routes.php of tasks app (it will register two restful resources): - * $routes = array( - * 'resources' => array( - * 'lists' => array('url' => '/tasklists'), - * 'tasks' => array('url' => '/tasklists/{listId}/tasks') - * ) - * ); - * - * $a = new TasksApp(); - * $a->registerRoutes($this, $routes); - * - * @param \OCP\Route\IRouter $router - * @param array $routes - * @since 6.0.0 - * @suppress PhanAccessMethodInternal - * @deprecated 20.0.0 Just return an array from your routes.php - */ - public function registerRoutes(IRouter $router, array $routes) { - if (!($router instanceof Router)) { - throw new \RuntimeException('Can only setup routes with real router'); - } - - $routeConfig = new RouteConfig($this->container, $router, $routes); - $routeConfig->register(); - } - - /** * This function is called by the routing component to fire up the frameworks dispatch mechanism. * * Example code in routes.php of the task app: diff --git a/lib/public/AppFramework/Attribute/ASince.php b/lib/public/AppFramework/Attribute/ASince.php new file mode 100644 index 00000000000..1e0c45348cf --- /dev/null +++ b/lib/public/AppFramework/Attribute/ASince.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Abstract base attribute to declare an API's stability. + * + * @since 32.0.0 + */ +#[Consumable(since: '32.0.0')] +abstract class ASince { + /** + * @param string $since For shipped apps and server code such as core/ and lib/, + * this should be the server version. For other apps it + * should be the semantic app version. + */ + public function __construct( + protected string $since, + ) { + } + + public function getSince(): string { + return $this->since; + } +} diff --git a/lib/public/AppFramework/Attribute/Catchable.php b/lib/public/AppFramework/Attribute/Catchable.php new file mode 100644 index 00000000000..d45401550f6 --- /dev/null +++ b/lib/public/AppFramework/Attribute/Catchable.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the exception is "catchable" by apps. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class Catchable extends ASince { +} diff --git a/lib/public/AppFramework/Attribute/Consumable.php b/lib/public/AppFramework/Attribute/Consumable.php new file mode 100644 index 00000000000..2175bb0af88 --- /dev/null +++ b/lib/public/AppFramework/Attribute/Consumable.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the API stability is limited to "consuming" the + * class, interface, enum, etc. Apps are not allowed to implement or replace them. + * + * For events use @see \OCP\AppFramework\Attribute\Listenable + * For exceptions use @see \OCP\AppFramework\Attribute\Catchable + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class Consumable extends ASince { +} diff --git a/lib/public/AppFramework/Attribute/Dispatchable.php b/lib/public/AppFramework/Attribute/Dispatchable.php new file mode 100644 index 00000000000..ff703d4749e --- /dev/null +++ b/lib/public/AppFramework/Attribute/Dispatchable.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the event is "dispatchable" by apps. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class Dispatchable extends ASince { +} diff --git a/lib/public/AppFramework/Attribute/ExceptionalImplementable.php b/lib/public/AppFramework/Attribute/ExceptionalImplementable.php new file mode 100644 index 00000000000..23e9f830d9b --- /dev/null +++ b/lib/public/AppFramework/Attribute/ExceptionalImplementable.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the API marked as Consumable/Listenable/Catchable + * has an exception and is Implementable/Dispatchable/Throwable by a dedicated + * app. Changes to such an API have to be communicated to the affected app maintainers. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class ExceptionalImplementable { + public function __construct( + protected string $app, + protected ?string $class = null, + ) { + } + + public function getApp(): string { + return $this->app; + } + + public function getClass(): ?string { + return $this->class; + } +} diff --git a/lib/public/AppFramework/Attribute/Implementable.php b/lib/public/AppFramework/Attribute/Implementable.php new file mode 100644 index 00000000000..40ce0e0cf06 --- /dev/null +++ b/lib/public/AppFramework/Attribute/Implementable.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the API stability is limited to "implementing" the + * class, interface, enum, etc. + * + * For events use @see \OCP\AppFramework\Attribute\Dispatchable + * For exceptions use @see \OCP\AppFramework\Attribute\Throwable + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class Implementable extends ASince { +} diff --git a/lib/public/AppFramework/Attribute/Listenable.php b/lib/public/AppFramework/Attribute/Listenable.php new file mode 100644 index 00000000000..98c2ca78690 --- /dev/null +++ b/lib/public/AppFramework/Attribute/Listenable.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the event is "listenable" by apps. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class Listenable extends ASince { +} diff --git a/lib/public/AppFramework/Attribute/Throwable.php b/lib/public/AppFramework/Attribute/Throwable.php new file mode 100644 index 00000000000..2c763c76b4c --- /dev/null +++ b/lib/public/AppFramework/Attribute/Throwable.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Attribute; + +use Attribute; + +/** + * Attribute to declare that the exception is "throwable" by apps. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] +#[Consumable(since: '32.0.0')] +#[Implementable(since: '32.0.0')] +class Throwable extends ASince { +} diff --git a/lib/public/AppFramework/AuthPublicShareController.php b/lib/public/AppFramework/AuthPublicShareController.php index 00834506b05..28a92fedcc9 100644 --- a/lib/public/AppFramework/AuthPublicShareController.php +++ b/lib/public/AppFramework/AuthPublicShareController.php @@ -3,31 +3,15 @@ declare(strict_types=1); /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Tim Obert <tobert@w-commerce.de> - * @author TimObert <tobert@w-commerce.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework; +use OCP\AppFramework\Http\Attribute\BruteForceProtection; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\PublicPage; +use OCP\AppFramework\Http\Attribute\UseSession; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\IRequest; @@ -53,23 +37,22 @@ abstract class AuthPublicShareController extends PublicShareController { * @since 14.0.0 */ public function __construct(string $appName, - IRequest $request, - ISession $session, - IURLGenerator $urlGenerator) { + IRequest $request, + ISession $session, + IURLGenerator $urlGenerator) { parent::__construct($appName, $request, $session); $this->urlGenerator = $urlGenerator; } /** - * @PublicPage - * @NoCSRFRequired - * * Show the authentication page * The form has to submit to the authenticate method route * * @since 14.0.0 */ + #[NoCSRFRequired] + #[PublicPage] public function showAuthenticate(): TemplateResponse { return new TemplateResponse('core', 'publicshareauth', [], 'guest'); } @@ -129,7 +112,7 @@ abstract class AuthPublicShareController extends PublicShareController { } /** - * Function called after successfull authentication + * Function called after successful authentication * * You can use this to do some logging for example * @@ -139,14 +122,13 @@ abstract class AuthPublicShareController extends PublicShareController { } /** - * @UseSession - * @PublicPage - * @BruteForceProtection(action=publicLinkAuth) - * * Authenticate the share * * @since 14.0.0 */ + #[BruteForceProtection(action: 'publicLinkAuth')] + #[PublicPage] + #[UseSession] final public function authenticate(string $password = '', string $passwordRequest = 'no', string $identityToken = '') { // Already authenticated if ($this->isAuthenticated()) { @@ -207,10 +189,10 @@ abstract class AuthPublicShareController extends PublicShareController { private function getRoute(string $function): string { $app = strtolower($this->appName); $class = (new \ReflectionClass($this))->getShortName(); - if (substr($class, -10) === 'Controller') { + if (str_ends_with($class, 'Controller')) { $class = substr($class, 0, -10); } - return $app .'.'. $class .'.'. $function; + return $app . '.' . $class . '.' . $function; } /** diff --git a/lib/public/AppFramework/Bootstrap/IBootContext.php b/lib/public/AppFramework/Bootstrap/IBootContext.php index 72a9602217d..cdf3a0af732 100644 --- a/lib/public/AppFramework/Bootstrap/IBootContext.php +++ b/lib/public/AppFramework/Bootstrap/IBootContext.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Bootstrap; diff --git a/lib/public/AppFramework/Bootstrap/IBootstrap.php b/lib/public/AppFramework/Bootstrap/IBootstrap.php index 8ebb377c152..7260d2b77a1 100644 --- a/lib/public/AppFramework/Bootstrap/IBootstrap.php +++ b/lib/public/AppFramework/Bootstrap/IBootstrap.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Bootstrap; @@ -42,8 +25,6 @@ interface IBootstrap { * At this stage you can assume that all services are registered and the DI * container(s) are ready to be queried. * - * This is also the state where an optional `appinfo/app.php` was loaded. - * * @param IBootContext $context * * @since 20.0.0 diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 6350169510f..70b35228c87 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -3,28 +3,8 @@ declare(strict_types=1); /** - * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Bootstrap; @@ -37,8 +17,13 @@ use OCP\Collaboration\Reference\IReferenceProvider; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\IContainer; +use OCP\Mail\Provider\IProvider as IMailProvider; use OCP\Notification\INotifier; use OCP\Preview\IProviderV2; +use OCP\SpeechToText\ISpeechToTextProvider; +use OCP\TextProcessing\IProvider as ITextProcessingProvider; +use OCP\TextToImage\IProvider as ITextToImageProvider; +use OCP\Translation\ITranslationProvider; /** * The context object passed to IBootstrap::register @@ -84,7 +69,7 @@ interface IRegistrationContext { * @param string $name * @param callable $factory * @psalm-param callable(\Psr\Container\ContainerInterface): mixed $factory - * @param bool $shared + * @param bool $shared If set to true the factory result will be cached otherwise every query will call the factory again * * @return void * @see IContainer::registerService() @@ -126,7 +111,7 @@ interface IRegistrationContext { * @param string $event preferably the fully-qualified class name of the Event sub class to listen for * @psalm-param string|class-string<T> $event preferably the fully-qualified class name of the Event sub class to listen for * @param string $listener fully qualified class name (or ::class notation) of a \OCP\EventDispatcher\IEventListener that can be built by the DI container - * @psalm-param class-string<\OCP\EventDispatcher\IEventListener> $listener fully qualified class name that can be built by the DI container + * @psalm-param class-string<\OCP\EventDispatcher\IEventListener<T>> $listener fully qualified class name that can be built by the DI container * @param int $priority The higher this value, the earlier an event * listener will be triggered in the chain (defaults to 0) * @@ -208,6 +193,36 @@ interface IRegistrationContext { public function registerWellKnownHandler(string $class): void; /** + * Register a custom SpeechToText provider class that can provide transcription + * of audio through the OCP\SpeechToText APIs + * + * @param string $providerClass + * @psalm-param class-string<ISpeechToTextProvider> $providerClass + * @since 27.0.0 + */ + public function registerSpeechToTextProvider(string $providerClass): void; + + /** + * Register a custom text processing provider class that provides a promptable language model + * through the OCP\TextProcessing APIs + * + * @param string $providerClass + * @psalm-param class-string<ITextProcessingProvider> $providerClass + * @since 27.1.0 + */ + public function registerTextProcessingProvider(string $providerClass): void; + + /** + * Register a custom text2image provider class that provides the possibility to generate images + * through the OCP\TextToImage APIs + * + * @param string $providerClass + * @psalm-param class-string<ITextToImageProvider> $providerClass + * @since 28.0.0 + */ + public function registerTextToImageProvider(string $providerClass): void; + + /** * Register a custom template provider class that is able to inject custom templates * in addition to the user defined ones * @@ -218,6 +233,16 @@ interface IRegistrationContext { public function registerTemplateProvider(string $providerClass): void; /** + * Register a custom translation provider class that can provide translation + * between languages through the OCP\Translation APIs + * + * @param string $providerClass + * @psalm-param class-string<ITranslationProvider> $providerClass + * @since 21.0.0 + */ + public function registerTranslationProvider(string $providerClass): void; + + /** * Register an INotifier class * * @param string $notifierClass @@ -308,6 +333,14 @@ interface IRegistrationContext { public function registerCalendarRoomBackend(string $class): void; /** + * @param string $class + * @psalm-param class-string<\OCP\Calendar\Room\IBackend> $actionClass + * @return void + * @since 29.0.0 + */ + public function registerTeamResourceProvider(string $class): void; + + /** * Register an implementation of \OCP\UserMigration\IMigrator that * will handle the implementation of a migrator * @@ -338,4 +371,80 @@ interface IRegistrationContext { * @since 26.0.0 */ public function registerPublicShareTemplateProvider(string $class): void; + + /** + * Register an implementation of \OCP\SetupCheck\ISetupCheck that + * will handle the implementation of a setup check + * + * @param class-string<\OCP\SetupCheck\ISetupCheck> $setupCheckClass + * @since 28.0.0 + */ + public function registerSetupCheck(string $setupCheckClass): void; + + /** + * Register an implementation of \OCP\Settings\IDeclarativeSettings that + * will handle the implementation of declarative settings + * + * @param string $declarativeSettingsClass + * @psalm-param class-string<\OCP\Settings\IDeclarativeSettingsForm> $declarativeSettingsClass + * @return void + * @since 29.0.0 + */ + public function registerDeclarativeSettings(string $declarativeSettingsClass): void; + + /** + * Register an implementation of \OCP\TaskProcessing\IProvider that + * will handle the implementation of task processing + * + * @param string $taskProcessingProviderClass + * @psalm-param class-string<\OCP\TaskProcessing\IProvider> $taskProcessingProviderClass + * @return void + * @since 30.0.0 + */ + public function registerTaskProcessingProvider(string $taskProcessingProviderClass): void; + + /** + * Register an implementation of \OCP\TaskProcessing\ITaskType that + * will handle the implementation of a task processing type + * + * @param string $taskProcessingTaskTypeClass + * @psalm-param class-string<\OCP\TaskProcessing\ITaskType> $taskProcessingTaskTypeClass + * @return void + * @since 30.0.0 + */ + public function registerTaskProcessingTaskType(string $taskProcessingTaskTypeClass): void; + + /** + * Register an implementation of \OCP\Files\Conversion\IConversionProvider + * that will handle the conversion of files from one MIME type to another + * + * @param string $class + * @psalm-param class-string<\OCP\Files\Conversion\IConversionProvider> $class + * + * @return void + * + * @since 31.0.0 + */ + public function registerFileConversionProvider(string $class): void; + + /** + * Register a mail provider + * + * @param string $class + * @psalm-param class-string<IMailProvider> $class + * @since 30.0.0 + */ + public function registerMailProvider(string $class): void; + + + /** + * Register an implementation of \OCP\Config\Lexicon\IConfigLexicon that + * will handle the config lexicon + * + * @param string $configLexiconClass + * + * @psalm-param class-string<\OCP\Config\Lexicon\ILexicon> $configLexiconClass + * @since 31.0.0 + */ + public function registerConfigLexicon(string $configLexiconClass): void; } diff --git a/lib/public/AppFramework/Controller.php b/lib/public/AppFramework/Controller.php index 89cfd2e55fc..cdeaac99366 100644 --- a/lib/public/AppFramework/Controller.php +++ b/lib/public/AppFramework/Controller.php @@ -1,30 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Donquixote <marjunebatac@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * @author Vincent Petry <vincent@nextcloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; @@ -65,7 +44,7 @@ abstract class Controller { * @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0 */ public function __construct($appName, - IRequest $request) { + IRequest $request) { $this->appName = $appName; $this->request = $request; @@ -91,6 +70,9 @@ abstract class Controller { if ($data->getLastModified() !== null) { $response->setLastModified($data->getLastModified()); } + if ($data->isThrottled()) { + $response->throttle($data->getThrottleMetadata()); + } return $response; } @@ -141,7 +123,7 @@ abstract class Controller { /** * Serializes and formats a response * @param mixed $response the value that was returned from a controller and - * is not a Response instance + * is not a Response instance * @param string $format the format for which a formatter has been registered * @throws \DomainException if format does not match a registered formatter * @return Response @@ -153,7 +135,7 @@ abstract class Controller { return $responder($response); } - throw new \DomainException('No responder registered for format '. - $format . '!'); + throw new \DomainException('No responder registered for format ' + . $format . '!'); } } diff --git a/lib/public/AppFramework/Db/DoesNotExistException.php b/lib/public/AppFramework/Db/DoesNotExistException.php index 58e86528795..416268b27c1 100644 --- a/lib/public/AppFramework/Db/DoesNotExistException.php +++ b/lib/public/AppFramework/Db/DoesNotExistException.php @@ -1,29 +1,10 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Db; diff --git a/lib/public/AppFramework/Db/Entity.php b/lib/public/AppFramework/Db/Entity.php index 34cd297e57e..3094070af5f 100644 --- a/lib/public/AppFramework/Db/Entity.php +++ b/lib/public/AppFramework/Db/Entity.php @@ -1,30 +1,14 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Db; +use OCP\DB\Types; + use function lcfirst; use function substr; @@ -41,12 +25,13 @@ abstract class Entity { public $id; private array $_updatedFields = []; + /** @var array<string, \OCP\DB\Types::*> */ private array $_fieldTypes = ['id' => 'integer']; /** * Simple alternative constructor for building entities from a request * @param array $params the array which was obtained via $this->params('key') - * in the controller + * in the controller * @since 7.0.0 */ public static function fromParams(array $params): static { @@ -70,9 +55,8 @@ abstract class Entity { $instance = new static(); foreach ($row as $key => $value) { - $prop = ucfirst($instance->columnToProperty($key)); - $setter = 'set' . $prop; - $instance->$setter($value); + $prop = $instance->columnToProperty($key); + $instance->setter($prop, [$value]); } $instance->resetUpdatedFields(); @@ -82,10 +66,10 @@ abstract class Entity { /** - * @return array with attribute and type + * @return array<string, \OCP\DB\Types::*> with attribute and type * @since 7.0.0 */ - public function getFieldTypes() { + public function getFieldTypes(): array { return $this->_fieldTypes; } @@ -94,50 +78,76 @@ abstract class Entity { * Marks the entity as clean needed for setting the id after the insertion * @since 7.0.0 */ - public function resetUpdatedFields() { + public function resetUpdatedFields(): void { $this->_updatedFields = []; } /** * Generic setter for properties + * + * @throws \InvalidArgumentException * @since 7.0.0 + * */ protected function setter(string $name, array $args): void { // setters should only work for existing attributes - if (property_exists($this, $name)) { - if ($this->$name === $args[0]) { - return; - } - $this->markFieldUpdated($name); - - // if type definition exists, cast to correct type - if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) { - $type = $this->_fieldTypes[$name]; - if ($type === 'blob') { - // (B)LOB is treated as string when we read from the DB - if (is_resource($args[0])) { - $args[0] = stream_get_contents($args[0]); - } - $type = 'string'; + if (!property_exists($this, $name)) { + throw new \BadFunctionCallException($name . ' is not a valid attribute'); + } + + if ($args[0] === $this->$name) { + return; + } + $this->markFieldUpdated($name); + + // if type definition exists, cast to correct type + if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) { + $type = $this->_fieldTypes[$name]; + if ($type === Types::BLOB) { + // (B)LOB is treated as string when we read from the DB + if (is_resource($args[0])) { + $args[0] = stream_get_contents($args[0]); } + $type = Types::STRING; + } - if ($type === 'datetime') { + switch ($type) { + case Types::BIGINT: + case Types::SMALLINT: + settype($args[0], Types::INTEGER); + break; + case Types::BINARY: + case Types::DECIMAL: + case Types::TEXT: + settype($args[0], Types::STRING); + break; + case Types::TIME: + case Types::DATE: + case Types::DATETIME: + case Types::DATETIME_TZ: if (!$args[0] instanceof \DateTime) { $args[0] = new \DateTime($args[0]); } - } elseif ($type === 'json') { + break; + case Types::TIME_IMMUTABLE: + case Types::DATE_IMMUTABLE: + case Types::DATETIME_IMMUTABLE: + case Types::DATETIME_TZ_IMMUTABLE: + if (!$args[0] instanceof \DateTimeImmutable) { + $args[0] = new \DateTimeImmutable($args[0]); + } + break; + case Types::JSON: if (!is_array($args[0])) { $args[0] = json_decode($args[0], true); } - } else { + break; + default: settype($args[0], $type); - } } - $this->$name = $args[0]; - } else { - throw new \BadFunctionCallException($name . - ' is not a valid attribute'); } + $this->$name = $args[0]; + } /** @@ -149,8 +159,8 @@ abstract class Entity { if (property_exists($this, $name)) { return $this->$name; } else { - throw new \BadFunctionCallException($name . - ' is not a valid attribute'); + throw new \BadFunctionCallException($name + . ' is not a valid attribute'); } } @@ -163,15 +173,15 @@ abstract class Entity { * @since 7.0.0 */ public function __call(string $methodName, array $args) { - if (strpos($methodName, 'set') === 0) { + if (str_starts_with($methodName, 'set')) { $this->setter(lcfirst(substr($methodName, 3)), $args); - } elseif (strpos($methodName, 'get') === 0) { + } elseif (str_starts_with($methodName, 'get')) { return $this->getter(lcfirst(substr($methodName, 3))); } elseif ($this->isGetterForBoolProperty($methodName)) { return $this->getter(lcfirst(substr($methodName, 2))); } else { - throw new \BadFunctionCallException($methodName . - ' does not exist'); + throw new \BadFunctionCallException($methodName + . ' does not exist'); } } @@ -181,9 +191,9 @@ abstract class Entity { * @since 18.0.0 */ protected function isGetterForBoolProperty(string $methodName): bool { - if (strpos($methodName, 'is') === 0) { + if (str_starts_with($methodName, 'is')) { $fieldName = lcfirst(substr($methodName, 2)); - return isset($this->_fieldTypes[$fieldName]) && strpos($this->_fieldTypes[$fieldName], 'bool') === 0; + return isset($this->_fieldTypes[$fieldName]) && str_starts_with($this->_fieldTypes[$fieldName], 'bool'); } return false; } @@ -200,16 +210,17 @@ abstract class Entity { /** * Transform a database columnname to a property + * * @param string $columnName the name of the column * @return string the property name * @since 7.0.0 */ - public function columnToProperty($columnName) { + public function columnToProperty(string $columnName) { $parts = explode('_', $columnName); - $property = null; + $property = ''; foreach ($parts as $part) { - if ($property === null) { + if ($property === '') { $property = $part; } else { $property .= ucfirst($part); @@ -222,16 +233,17 @@ abstract class Entity { /** * Transform a property to a database column name + * * @param string $property the name of the property * @return string the column name * @since 7.0.0 */ - public function propertyToColumn($property) { + public function propertyToColumn(string $property): string { $parts = preg_split('/(?=[A-Z])/', $property); - $column = null; + $column = ''; foreach ($parts as $part) { - if ($column === null) { + if ($column === '') { $column = $part; } else { $column .= '_' . lcfirst($part); @@ -246,19 +258,33 @@ abstract class Entity { * @return array array of updated fields for update query * @since 7.0.0 */ - public function getUpdatedFields() { + public function getUpdatedFields(): array { return $this->_updatedFields; } /** - * Adds type information for a field so that its automatically casted to + * Adds type information for a field so that it's automatically cast to * that value once its being returned from the database + * * @param string $fieldName the name of the attribute - * @param string $type the type which will be used to call settype() + * @param \OCP\DB\Types::* $type the type which will be used to match a cast + * @since 31.0.0 Parameter $type is now restricted to {@see \OCP\DB\Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly. * @since 7.0.0 */ - protected function addType($fieldName, $type) { + protected function addType(string $fieldName, string $type): void { + /** @psalm-suppress TypeDoesNotContainType */ + if (in_array($type, ['bool', 'double', 'int', 'array', 'object'], true)) { + // Mapping legacy strings to the actual types + $type = match ($type) { + 'int' => Types::INTEGER, + 'bool' => Types::BOOLEAN, + 'double' => Types::FLOAT, + 'array', + 'object' => Types::STRING, + }; + } + $this->_fieldTypes[$fieldName] = $type; } @@ -266,12 +292,13 @@ abstract class Entity { /** * Slugify the value of a given attribute * Warning: This doesn't result in a unique value + * * @param string $attributeName the name of the attribute, which value should be slugified * @return string slugified value * @since 7.0.0 * @deprecated 24.0.0 */ - public function slugify($attributeName) { + public function slugify(string $attributeName): string { // toSlug should only work for existing attributes if (property_exists($this, $attributeName)) { $value = $this->$attributeName; @@ -280,9 +307,8 @@ abstract class Entity { $value = strtolower($value); // trim '-' return trim($value, '-'); - } else { - throw new \BadFunctionCallException($attributeName . - ' is not a valid attribute'); } + + throw new \BadFunctionCallException($attributeName . ' is not a valid attribute'); } } diff --git a/lib/public/AppFramework/Db/IMapperException.php b/lib/public/AppFramework/Db/IMapperException.php index a4af3cfa925..3e91422a89f 100644 --- a/lib/public/AppFramework/Db/IMapperException.php +++ b/lib/public/AppFramework/Db/IMapperException.php @@ -1,33 +1,14 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Db; /** * @since 16.0.0 */ -interface IMapperException { +interface IMapperException extends \Throwable { } diff --git a/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php b/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php index 6ae45849d83..e83bc1647d7 100644 --- a/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php +++ b/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php @@ -1,29 +1,10 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Db; diff --git a/lib/public/AppFramework/Db/QBMapper.php b/lib/public/AppFramework/Db/QBMapper.php index 57f4cba2ff5..7fb5b2a9afd 100644 --- a/lib/public/AppFramework/Db/QBMapper.php +++ b/lib/public/AppFramework/Db/QBMapper.php @@ -1,37 +1,16 @@ <?php declare(strict_types=1); - /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Anna Larch <anna@nextcloud.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Marius David Wieschollek <git.public@mdns.eu> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Db; +use Generator; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\Types; use OCP\IDBConnection; /** @@ -55,12 +34,11 @@ abstract class QBMapper { /** * @param IDBConnection $db Instance of the Db abstraction layer * @param string $tableName the name of the table. set this to allow entity - * @param string|null $entityClass the name of the entity that the sql should be - * @psalm-param class-string<T>|null $entityClass the name of the entity that the sql should be - * mapped to queries without using sql + * @param class-string<T>|null $entityClass the name of the entity that the sql should be + * mapped to queries without using sql * @since 14.0.0 */ - public function __construct(IDBConnection $db, string $tableName, string $entityClass = null) { + public function __construct(IDBConnection $db, string $tableName, ?string $entityClass = null) { $this->db = $db; $this->tableName = $tableName; @@ -226,7 +204,7 @@ abstract class QBMapper { * Returns the type parameter for the QueryBuilder for a specific property * of the $entity * - * @param Entity $entity The entity to get the types from + * @param Entity $entity The entity to get the types from * @psalm-param T $entity * @param string $property The property of $entity to get the type for * @return int|string @@ -241,18 +219,33 @@ abstract class QBMapper { switch ($types[ $property ]) { case 'int': - case 'integer': + case Types::INTEGER: + case Types::SMALLINT: return IQueryBuilder::PARAM_INT; - case 'string': + case Types::STRING: return IQueryBuilder::PARAM_STR; case 'bool': - case 'boolean': + case Types::BOOLEAN: return IQueryBuilder::PARAM_BOOL; - case 'blob': + case Types::BLOB: return IQueryBuilder::PARAM_LOB; - case 'datetime': - return IQueryBuilder::PARAM_DATE; - case 'json': + case Types::DATE: + return IQueryBuilder::PARAM_DATETIME_MUTABLE; + case Types::DATETIME: + return IQueryBuilder::PARAM_DATETIME_MUTABLE; + case Types::DATETIME_TZ: + return IQueryBuilder::PARAM_DATETIME_TZ_MUTABLE; + case Types::DATE_IMMUTABLE: + return IQueryBuilder::PARAM_DATE_IMMUTABLE; + case Types::DATETIME_IMMUTABLE: + return IQueryBuilder::PARAM_DATETIME_IMMUTABLE; + case Types::DATETIME_TZ_IMMUTABLE: + return IQueryBuilder::PARAM_DATETIME_TZ_IMMUTABLE; + case Types::TIME: + return IQueryBuilder::PARAM_TIME_MUTABLE; + case Types::TIME_IMMUTABLE: + return IQueryBuilder::PARAM_TIME_IMMUTABLE; + case Types::JSON: return IQueryBuilder::PARAM_JSON; } @@ -303,8 +296,8 @@ abstract class QBMapper { * @since 14.0.0 */ private function buildDebugMessage(string $msg, IQueryBuilder $sql): string { - return $msg . - ': query "' . $sql->getSQL() . '"; '; + return $msg + . ': query "' . $sql->getSQL() . '"; '; } @@ -318,7 +311,8 @@ abstract class QBMapper { * @since 14.0.0 */ protected function mapRowToEntity(array $row): Entity { - return \call_user_func($this->entityClass .'::fromRow', $row); + unset($row['DOCTRINE_ROWNUM']); // remove doctrine/dbal helper column + return \call_user_func($this->entityClass . '::fromRow', $row); } @@ -326,8 +320,8 @@ abstract class QBMapper { * Runs a sql query and returns an array of entities * * @param IQueryBuilder $query - * @return Entity[] all fetched entities - * @psalm-return T[] all fetched entities + * @return list<Entity> all fetched entities + * @psalm-return list<T> all fetched entities * @throws Exception * @since 14.0.0 */ @@ -344,6 +338,26 @@ abstract class QBMapper { } } + /** + * Runs a sql query and yields each resulting entity to obtain database entries in a memory-efficient way + * + * @param IQueryBuilder $query + * @return Generator Generator of fetched entities + * @psalm-return Generator<T> Generator of fetched entities + * @throws Exception + * @since 30.0.0 + */ + protected function yieldEntities(IQueryBuilder $query): Generator { + $result = $query->executeQuery(); + try { + while ($row = $result->fetch()) { + yield $this->mapRowToEntity($row); + } + } finally { + $result->closeCursor(); + } + } + /** * Returns an db result and throws exceptions when there are more or less diff --git a/lib/public/AppFramework/Db/TTransactional.php b/lib/public/AppFramework/Db/TTransactional.php index 1e02a129e69..8dd275e5420 100644 --- a/lib/public/AppFramework/Db/TTransactional.php +++ b/lib/public/AppFramework/Db/TTransactional.php @@ -1,33 +1,17 @@ <?php declare(strict_types=1); - -/* - * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. +/** + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCP\AppFramework\Db; +use OC\DB\Exceptions\DbalException; use OCP\DB\Exception; use OCP\IDBConnection; use Throwable; +use function OCP\Log\logger; /** * Helper trait for transactional operations @@ -66,4 +50,39 @@ trait TTransactional { throw $e; } } + + /** + * Wrapper around atomic() to retry after a retryable exception occurred + * + * Certain transactions might need to be retried. This is especially useful + * in highly concurrent requests where a deadlocks is thrown by the database + * without waiting for the lock to be freed (e.g. due to MySQL/MariaDB deadlock + * detection) + * + * @template T + * @param callable $fn + * @psalm-param callable():T $fn + * @param IDBConnection $db + * @param int $maxRetries + * + * @return mixed the result of the passed callable + * @psalm-return T + * + * @throws Exception for possible errors of commit or rollback or the custom operations within the closure + * @throws Throwable any other error caused by the closure + * + * @since 27.0.0 + */ + protected function atomicRetry(callable $fn, IDBConnection $db, int $maxRetries = 3): mixed { + for ($i = 0; $i < $maxRetries; $i++) { + try { + return $this->atomic($fn, $db); + } catch (DbalException $e) { + if (!$e->isRetryable() || $i === ($maxRetries - 1)) { + throw $e; + } + logger('core')->warning('Retrying operation after retryable exception.', [ 'exception' => $e ]); + } + } + } } diff --git a/lib/public/AppFramework/Http.php b/lib/public/AppFramework/Http.php index 8b3cde6875e..72bdadc9d17 100644 --- a/lib/public/AppFramework/Http.php +++ b/lib/public/AppFramework/Http.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; @@ -29,63 +12,298 @@ namespace OCP\AppFramework; * @since 6.0.0 */ class Http { + /** + * @since 6.0.0 + */ public const STATUS_CONTINUE = 100; + + /** + * @since 6.0.0 + */ public const STATUS_SWITCHING_PROTOCOLS = 101; + + /** + * @since 6.0.0 + */ public const STATUS_PROCESSING = 102; + + /** + * @since 6.0.0 + */ public const STATUS_OK = 200; + + /** + * @since 6.0.0 + */ public const STATUS_CREATED = 201; + + /** + * @since 6.0.0 + */ public const STATUS_ACCEPTED = 202; + + /** + * @since 6.0.0 + */ public const STATUS_NON_AUTHORATIVE_INFORMATION = 203; + + /** + * @since 6.0.0 + */ public const STATUS_NO_CONTENT = 204; + + /** + * @since 6.0.0 + */ public const STATUS_RESET_CONTENT = 205; + + /** + * @since 6.0.0 + */ public const STATUS_PARTIAL_CONTENT = 206; + + /** + * @since 6.0.0 + */ public const STATUS_MULTI_STATUS = 207; + + /** + * @since 6.0.0 + */ public const STATUS_ALREADY_REPORTED = 208; + + /** + * @since 6.0.0 + */ public const STATUS_IM_USED = 226; + + /** + * @since 6.0.0 + */ public const STATUS_MULTIPLE_CHOICES = 300; + + /** + * @since 6.0.0 + */ public const STATUS_MOVED_PERMANENTLY = 301; + + /** + * @since 6.0.0 + */ public const STATUS_FOUND = 302; + + /** + * @since 6.0.0 + */ public const STATUS_SEE_OTHER = 303; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_MODIFIED = 304; + + /** + * @since 6.0.0 + */ public const STATUS_USE_PROXY = 305; + + /** + * @since 6.0.0 + */ public const STATUS_RESERVED = 306; + + /** + * @since 6.0.0 + */ public const STATUS_TEMPORARY_REDIRECT = 307; + + /** + * @since 6.0.0 + */ public const STATUS_BAD_REQUEST = 400; + + /** + * @since 6.0.0 + */ public const STATUS_UNAUTHORIZED = 401; + + /** + * @since 6.0.0 + */ public const STATUS_PAYMENT_REQUIRED = 402; + + /** + * @since 6.0.0 + */ public const STATUS_FORBIDDEN = 403; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_FOUND = 404; + + /** + * @since 6.0.0 + */ public const STATUS_METHOD_NOT_ALLOWED = 405; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_ACCEPTABLE = 406; + + /** + * @since 6.0.0 + */ public const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_TIMEOUT = 408; + + /** + * @since 6.0.0 + */ public const STATUS_CONFLICT = 409; + + /** + * @since 6.0.0 + */ public const STATUS_GONE = 410; + + /** + * @since 6.0.0 + */ public const STATUS_LENGTH_REQUIRED = 411; + + /** + * @since 6.0.0 + */ public const STATUS_PRECONDITION_FAILED = 412; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_URI_TOO_LONG = 414; + + /** + * @since 6.0.0 + */ public const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; + + /** + * @since 6.0.0 + */ public const STATUS_EXPECTATION_FAILED = 417; + + /** + * @since 6.0.0 + */ public const STATUS_IM_A_TEAPOT = 418; + + /** + * @since 6.0.0 + */ public const STATUS_UNPROCESSABLE_ENTITY = 422; + + /** + * @since 6.0.0 + */ public const STATUS_LOCKED = 423; + + /** + * @since 6.0.0 + */ public const STATUS_FAILED_DEPENDENCY = 424; + + /** + * @since 6.0.0 + */ public const STATUS_UPGRADE_REQUIRED = 426; + + /** + * @since 6.0.0 + */ public const STATUS_PRECONDITION_REQUIRED = 428; + + /** + * @since 6.0.0 + */ public const STATUS_TOO_MANY_REQUESTS = 429; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; + + /** + * @since 6.0.0 + */ public const STATUS_INTERNAL_SERVER_ERROR = 500; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_IMPLEMENTED = 501; + + /** + * @since 6.0.0 + */ public const STATUS_BAD_GATEWAY = 502; + + /** + * @since 6.0.0 + */ public const STATUS_SERVICE_UNAVAILABLE = 503; + + /** + * @since 6.0.0 + */ public const STATUS_GATEWAY_TIMEOUT = 504; + + /** + * @since 6.0.0 + */ public const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; + + /** + * @since 6.0.0 + */ public const STATUS_VARIANT_ALSO_NEGOTIATES = 506; + + /** + * @since 6.0.0 + */ public const STATUS_INSUFFICIENT_STORAGE = 507; + + /** + * @since 6.0.0 + */ public const STATUS_LOOP_DETECTED = 508; + + /** + * @since 6.0.0 + */ public const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_EXTENDED = 510; + + /** + * @since 6.0.0 + */ public const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; } diff --git a/lib/public/AppFramework/Http/Attribute/ARateLimit.php b/lib/public/AppFramework/Http/Attribute/ARateLimit.php new file mode 100644 index 00000000000..c06b1180ae3 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/ARateLimit.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +/** + * Attribute for controller methods that want to limit the times a logged-in + * user can call the endpoint in a given time period. + * + * @since 27.0.0 + */ +abstract class ARateLimit { + /** + * @param int $limit The maximum number of requests that can be made in the given period in seconds. + * @param int $period The time period in seconds. + * @since 27.0.0 + */ + public function __construct( + protected int $limit, + protected int $period, + ) { + } + + /** + * @since 27.0.0 + */ + public function getLimit(): int { + return $this->limit; + } + + /** + * @since 27.0.0 + */ + public function getPeriod(): int { + return $this->period; + } +} diff --git a/lib/public/AppFramework/Http/Attribute/AnonRateLimit.php b/lib/public/AppFramework/Http/Attribute/AnonRateLimit.php new file mode 100644 index 00000000000..f02f2b695c5 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/AnonRateLimit.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that want to limit the times a not logged-in + * guest can call the endpoint in a given time period. + * + * @since 27.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD)] +class AnonRateLimit extends ARateLimit { +} diff --git a/lib/public/AppFramework/Http/Attribute/ApiRoute.php b/lib/public/AppFramework/Http/Attribute/ApiRoute.php new file mode 100644 index 00000000000..1d61cfe7704 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/ApiRoute.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute can be used to define API routes on controller methods. + * + * It works in addition to the traditional routes.php method and has the same parameters + * (except for the `name` parameter which is not needed). + * + * @since 29.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class ApiRoute extends Route { + /** + * @inheritDoc + * + * @since 29.0.0 + */ + public function __construct( + protected string $verb, + protected string $url, + protected ?array $requirements = null, + protected ?array $defaults = null, + protected ?string $root = null, + protected ?string $postfix = null, + ) { + parent::__construct( + Route::TYPE_API, + $verb, + $url, + $requirements, + $defaults, + $root, + $postfix, + ); + } +} diff --git a/lib/public/AppFramework/Http/Attribute/AppApiAdminAccessWithoutUser.php b/lib/public/AppFramework/Http/Attribute/AppApiAdminAccessWithoutUser.php new file mode 100644 index 00000000000..6b78fee41af --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/AppApiAdminAccessWithoutUser.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for (sub)administrator controller methods that allow access for ExApps when the User is not set. + * + * @since 30.0.0 + */ +#[Attribute] +class AppApiAdminAccessWithoutUser { +} diff --git a/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php b/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php new file mode 100644 index 00000000000..83101143fc9 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; +use OCP\Settings\IDelegatedSettings; + +/** + * Attribute for controller methods that should be only accessible with + * full admin or partial admin permissions. + * + * @since 27.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class AuthorizedAdminSetting { + /** + * @param class-string<IDelegatedSettings> $settings A settings section the user needs to be able to access + * @since 27.0.0 + */ + public function __construct( + protected string $settings, + ) { + } + + /** + * + * @return class-string<IDelegatedSettings> + * @since 27.0.0 + */ + public function getSettings(): string { + return $this->settings; + } +} diff --git a/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php b/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php new file mode 100644 index 00000000000..0fc1a3b9b6d --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that want to protect passwords, keys, tokens + * or other data against brute force + * + * @since 27.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class BruteForceProtection { + /** + * @since 27.0.0 + */ + public function __construct( + protected string $action, + ) { + } + + /** + * @since 27.0.0 + */ + public function getAction(): string { + return $this->action; + } +} diff --git a/lib/public/AppFramework/Http/Attribute/CORS.php b/lib/public/AppFramework/Http/Attribute/CORS.php new file mode 100644 index 00000000000..ff639635635 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/CORS.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that can also be accessed by other websites. + * See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS for an explanation of the functionality and the security implications. + * See https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/rest_apis.html on how to implement it in your controller. + * + * @since 27.0.0 + */ +#[Attribute] +class CORS { +} diff --git a/lib/public/AppFramework/Http/Attribute/ExAppRequired.php b/lib/public/AppFramework/Http/Attribute/ExAppRequired.php new file mode 100644 index 00000000000..eb18da8027c --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/ExAppRequired.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that can only be accessed by ExApps + * + * @since 30.0.0 + */ +#[Attribute] +class ExAppRequired { +} diff --git a/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php b/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php new file mode 100644 index 00000000000..398116d786f --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute can be used to define Frontpage routes on controller methods. + * + * It works in addition to the traditional routes.php method and has the same parameters + * (except for the `name` parameter which is not needed). + * + * @since 29.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class FrontpageRoute extends Route { + /** + * @inheritDoc + * + * @since 29.0.0 + */ + public function __construct( + protected string $verb, + protected string $url, + protected ?array $requirements = null, + protected ?array $defaults = null, + protected ?string $root = null, + protected ?string $postfix = null, + ) { + parent::__construct( + Route::TYPE_FRONTPAGE, + $verb, + $url, + $requirements, + $defaults, + $root, + $postfix, + ); + } +} diff --git a/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php new file mode 100644 index 00000000000..114637935db --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that should be ignored when generating OpenAPI documentation + * + * @since 28.0.0 + * @deprecated 28.0.0 Use {@see OpenAPI} with {@see OpenAPI::SCOPE_IGNORE} instead: `#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]` + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)] +class IgnoreOpenAPI { +} diff --git a/lib/public/AppFramework/Http/Attribute/NoAdminRequired.php b/lib/public/AppFramework/Http/Attribute/NoAdminRequired.php new file mode 100644 index 00000000000..59c6cf86800 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/NoAdminRequired.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that can be accessed by any logged-in user + * + * @since 27.0.0 + */ +#[Attribute] +class NoAdminRequired { +} diff --git a/lib/public/AppFramework/Http/Attribute/NoCSRFRequired.php b/lib/public/AppFramework/Http/Attribute/NoCSRFRequired.php new file mode 100644 index 00000000000..ad7e569a3b9 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/NoCSRFRequired.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that are not CSRF protected + * + * @since 27.0.0 + */ +#[Attribute] +class NoCSRFRequired { +} diff --git a/lib/public/AppFramework/Http/Attribute/OpenAPI.php b/lib/public/AppFramework/Http/Attribute/OpenAPI.php new file mode 100644 index 00000000000..1b44b2a57fe --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/OpenAPI.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * With this attribute a controller or a method can be moved into a different + * scope or tag. Scopes should be seen as API consumers, tags can be used to group + * different routes inside the same scope. + * + * @since 28.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +class OpenAPI { + /** + * APIs used for normal user facing interaction with your app, + * e.g. when you would implement a mobile client or standalone frontend. + * + * @since 28.0.0 + */ + public const SCOPE_DEFAULT = 'default'; + + /** + * APIs used to administrate your app's configuration on an administrative level. + * Will be set automatically when admin permissions are required to access the route. + * + * @since 28.0.0 + */ + public const SCOPE_ADMINISTRATION = 'administration'; + + /** + * APIs used by servers to federate with each other. + * + * @since 28.0.0 + */ + public const SCOPE_FEDERATION = 'federation'; + + /** + * Ignore this controller or method in all generated OpenAPI specifications. + * + * @since 28.0.0 + */ + public const SCOPE_IGNORE = 'ignore'; + + /** + * APIs used by ExApps. + * Will be set automatically when an ExApp is required to access the route. + * + * @since 30.0.0 + */ + public const SCOPE_EX_APP = 'ex_app'; + + /** + * @param self::SCOPE_*|string $scope Scopes are used to define different clients. + * It is recommended to go with the scopes available as self::SCOPE_* constants, + * but in exotic cases other APIs might need documentation as well, + * then a free string can be provided (but it should be `a-z` only). + * @param ?list<string> $tags Tags can be used to group routes inside a scope + * for easier implementation and reviewing of the API specification. + * It defaults to the controller name in snake_case (should be `a-z` and underscore only). + * @since 28.0.0 + */ + public function __construct( + protected string $scope = self::SCOPE_DEFAULT, + protected ?array $tags = null, + ) { + } + + /** + * @since 28.0.0 + */ + public function getScope(): string { + return $this->scope; + } + + /** + * @return ?list<string> + * @since 28.0.0 + */ + public function getTags(): ?array { + return $this->tags; + } +} diff --git a/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php b/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php new file mode 100644 index 00000000000..c41e5aa2445 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that require the password to be confirmed with in the last 30 minutes + * + * @since 27.0.0 + */ +#[Attribute] +class PasswordConfirmationRequired { + /** + * @param bool $strict - Whether password confirmation needs to happen in the request. + * + * @since 31.0.0 + */ + public function __construct( + protected bool $strict = false, + ) { + } + + /** + * @since 31.0.0 + */ + public function getStrict(): bool { + return $this->strict; + } + +} diff --git a/lib/public/AppFramework/Http/Attribute/PublicPage.php b/lib/public/AppFramework/Http/Attribute/PublicPage.php new file mode 100644 index 00000000000..85c1ed06f80 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/PublicPage.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that can also be accessed by not logged-in user + * + * @since 27.0.0 + */ +#[Attribute] +class PublicPage { +} diff --git a/lib/public/AppFramework/Http/Attribute/RequestHeader.php b/lib/public/AppFramework/Http/Attribute/RequestHeader.php new file mode 100644 index 00000000000..1d0fbbfa0c3 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/RequestHeader.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute allows documenting request headers and is primarily intended for OpenAPI documentation. + * It should be added whenever you use a request header in a controller method, in order to properly describe the header and its functionality. + * There are no checks that ensure the header is set, so you will still need to do this yourself in the controller method. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class RequestHeader { + /** + * @param lowercase-string $name The name of the request header + * @param non-empty-string $description The description of the request header + * @param bool $indirect Allow indirect usage of the header for example in a middleware. Enabling this turns off the check which ensures that the header must be referenced in the controller method. + */ + public function __construct( + protected string $name, + protected string $description, + protected bool $indirect = false, + ) { + } +} diff --git a/lib/public/AppFramework/Http/Attribute/Route.php b/lib/public/AppFramework/Http/Attribute/Route.php new file mode 100644 index 00000000000..45e977d64f8 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/Route.php @@ -0,0 +1,145 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute can be used to define routes on controller methods. + * + * It works in addition to the traditional routes.php method and has the same parameters + * (except for the `name` parameter which is not needed). + * + * @since 29.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class Route { + + /** + * Corresponds to the `ocs` key in routes.php + * + * @see ApiRoute + * @since 29.0.0 + */ + public const TYPE_API = 'ocs'; + + /** + * Corresponds to the `routes` key in routes.php + * + * @see FrontpageRoute + * @since 29.0.0 + */ + public const TYPE_FRONTPAGE = 'routes'; + + /** + * @param string $type Either Route::TYPE_API or Route::TYPE_FRONTPAGE. + * @psalm-param Route::TYPE_* $type + * @param string $verb HTTP method of the route. + * @psalm-param 'GET'|'HEAD'|'POST'|'PUT'|'DELETE'|'OPTIONS'|'PATCH' $verb + * @param string $url The path of the route. + * @param ?array<string, string> $requirements Array of regexes mapped to the path parameters. + * @param ?array<string, mixed> $defaults Array of default values mapped to the path parameters. + * @param ?string $root Custom root. For OCS all apps are allowed, but for index.php only some can use it. + * @param ?string $postfix Postfix for the route name. + * @since 29.0.0 + */ + public function __construct( + protected string $type, + protected string $verb, + protected string $url, + protected ?array $requirements = null, + protected ?array $defaults = null, + protected ?string $root = null, + protected ?string $postfix = null, + ) { + } + + /** + * @return array{ + * verb: string, + * url: string, + * requirements?: array<string, string>, + * defaults?: array<string, mixed>, + * root?: string, + * postfix?: string, + * } + * @since 29.0.0 + */ + public function toArray() { + $route = [ + 'verb' => $this->verb, + 'url' => $this->url, + ]; + + if ($this->requirements !== null) { + $route['requirements'] = $this->requirements; + } + if ($this->defaults !== null) { + $route['defaults'] = $this->defaults; + } + if ($this->root !== null) { + $route['root'] = $this->root; + } + if ($this->postfix !== null) { + $route['postfix'] = $this->postfix; + } + + return $route; + } + + /** + * @since 29.0.0 + */ + public function getType(): string { + return $this->type; + } + + /** + * @since 29.0.0 + */ + public function getVerb(): string { + return $this->verb; + } + + /** + * @since 29.0.0 + */ + public function getUrl(): string { + return $this->url; + } + + /** + * @since 29.0.0 + */ + public function getRequirements(): ?array { + return $this->requirements; + } + + /** + * @since 29.0.0 + */ + public function getDefaults(): ?array { + return $this->defaults; + } + + /** + * @since 29.0.0 + */ + public function getRoot(): ?string { + return $this->root; + } + + /** + * @since 29.0.0 + */ + public function getPostfix(): ?string { + return $this->postfix; + } +} diff --git a/lib/public/AppFramework/Http/Attribute/StrictCookiesRequired.php b/lib/public/AppFramework/Http/Attribute/StrictCookiesRequired.php new file mode 100644 index 00000000000..a2697847ca6 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/StrictCookiesRequired.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that require strict cookies + * + * @since 27.0.0 + */ +#[Attribute] +class StrictCookiesRequired { +} diff --git a/lib/public/AppFramework/Http/Attribute/SubAdminRequired.php b/lib/public/AppFramework/Http/Attribute/SubAdminRequired.php new file mode 100644 index 00000000000..38c4dd35f3c --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/SubAdminRequired.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that can be accessed by sub-admins + * + * @since 27.0.0 + */ +#[Attribute] +class SubAdminRequired { +} diff --git a/lib/public/AppFramework/Http/Attribute/UseSession.php b/lib/public/AppFramework/Http/Attribute/UseSession.php index 79185919def..f64b050144f 100644 --- a/lib/public/AppFramework/Http/Attribute/UseSession.php +++ b/lib/public/AppFramework/Http/Attribute/UseSession.php @@ -2,25 +2,9 @@ declare(strict_types=1); -/* - * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Attribute; diff --git a/lib/public/AppFramework/Http/Attribute/UserRateLimit.php b/lib/public/AppFramework/Http/Attribute/UserRateLimit.php new file mode 100644 index 00000000000..6fcf7127e89 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/UserRateLimit.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for controller methods that want to limit the times a logged-in + * user can call the endpoint in a given time period. + * + * @since 27.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD)] +class UserRateLimit extends ARateLimit { +} diff --git a/lib/public/AppFramework/Http/ContentSecurityPolicy.php b/lib/public/AppFramework/Http/ContentSecurityPolicy.php index 0e3a6a705d5..11ec79bbdb7 100644 --- a/lib/public/AppFramework/Http/ContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/ContentSecurityPolicy.php @@ -1,27 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author sualko <klaus@jsxc.org> - * @author Thomas Citharel <nextcloud@tcit.fr> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -44,15 +26,19 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy { protected $inlineScriptAllowed = false; /** @var bool Whether eval in JS scripts is allowed */ protected $evalScriptAllowed = false; + /** @var bool Whether WebAssembly compilation is allowed */ + protected ?bool $evalWasmAllowed = false; /** @var bool Whether strict-dynamic should be set */ protected $strictDynamicAllowed = false; + /** @var bool Whether strict-dynamic should be set for 'script-src-elem' */ + protected $strictDynamicAllowedOnScripts = true; /** @var array Domains from which scripts can get loaded */ protected $allowedScriptDomains = [ '\'self\'', ]; /** * @var bool Whether inline CSS is allowed - * TODO: Disallow per default + * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/13458 */ protected $inlineStyleAllowed = true; diff --git a/lib/public/AppFramework/Http/DataDisplayResponse.php b/lib/public/AppFramework/Http/DataDisplayResponse.php index 78ab343abd6..e1ded910328 100644 --- a/lib/public/AppFramework/Http/DataDisplayResponse.php +++ b/lib/public/AppFramework/Http/DataDisplayResponse.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Julius Härtl <jus@bitgrid.net> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -30,6 +13,9 @@ use OCP\AppFramework\Http; * Class DataDisplayResponse * * @since 8.1.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class DataDisplayResponse extends Response { /** @@ -41,17 +27,14 @@ class DataDisplayResponse extends Response { /** * @param string $data the data to display - * @param int $statusCode the Http status code, defaults to 200 - * @param array $headers additional key value based headers + * @param S $statusCode the Http status code, defaults to 200 + * @param H $headers additional key value based headers * @since 8.1.0 */ - public function __construct($data = '', $statusCode = Http::STATUS_OK, - $headers = []) { - parent::__construct(); + public function __construct(string $data = '', int $statusCode = Http::STATUS_OK, array $headers = []) { + parent::__construct($statusCode, $headers); $this->data = $data; - $this->setStatus($statusCode); - $this->setHeaders(array_merge($this->getHeaders(), $headers)); $this->addHeader('Content-Disposition', 'inline; filename=""'); } diff --git a/lib/public/AppFramework/Http/DataDownloadResponse.php b/lib/public/AppFramework/Http/DataDownloadResponse.php index 7f2bc73f6e2..ee6bcf0d0c5 100644 --- a/lib/public/AppFramework/Http/DataDownloadResponse.php +++ b/lib/public/AppFramework/Http/DataDownloadResponse.php @@ -1,32 +1,22 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; + /** * Class DataDownloadResponse * * @since 8.0.0 + * @template S of Http::STATUS_* + * @template C of string + * @template H of array<string, mixed> + * @template-extends DownloadResponse<Http::STATUS_*, string, array<string, mixed>> */ class DataDownloadResponse extends DownloadResponse { /** @@ -38,12 +28,14 @@ class DataDownloadResponse extends DownloadResponse { * Creates a response that prompts the user to download the text * @param string $data text to be downloaded * @param string $filename the name that the downloaded file should have - * @param string $contentType the mimetype that the downloaded file should have + * @param C $contentType the mimetype that the downloaded file should have + * @param S $status + * @param H $headers * @since 8.0.0 */ - public function __construct($data, $filename, $contentType) { + public function __construct(string $data, string $filename, string $contentType, int $status = Http::STATUS_OK, array $headers = []) { $this->data = $data; - parent::__construct($filename, $contentType); + parent::__construct($filename, $contentType, $status, $headers); } /** diff --git a/lib/public/AppFramework/Http/DataResponse.php b/lib/public/AppFramework/Http/DataResponse.php index e329b9c2975..2b54ce848ef 100644 --- a/lib/public/AppFramework/Http/DataResponse.php +++ b/lib/public/AppFramework/Http/DataResponse.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -30,34 +13,37 @@ use OCP\AppFramework\Http; * A generic DataResponse class that is used to return generic data responses * for responders to transform * @since 8.0.0 + * @psalm-type DataResponseType = array|int|float|string|bool|object|null|\stdClass|\JsonSerializable + * @template S of Http::STATUS_* + * @template-covariant T of DataResponseType + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class DataResponse extends Response { /** * response data - * @var array|int|float|string|bool|object + * @var T */ protected $data; /** - * @param array|int|float|string|bool|object $data the object or array that should be transformed - * @param int $statusCode the Http status code, defaults to 200 - * @param array $headers additional key value based headers + * @param T $data the object or array that should be transformed + * @param S $statusCode the Http status code, defaults to 200 + * @param H $headers additional key value based headers * @since 8.0.0 */ - public function __construct($data = [], $statusCode = Http::STATUS_OK, - array $headers = []) { - parent::__construct(); + public function __construct(mixed $data = [], int $statusCode = Http::STATUS_OK, array $headers = []) { + parent::__construct($statusCode, $headers); $this->data = $data; - $this->setStatus($statusCode); - $this->setHeaders(array_merge($this->getHeaders(), $headers)); } /** * Sets values in the data json array - * @param array|int|float|string|object $data an array or object which will be transformed + * @psalm-suppress InvalidTemplateParam + * @param T $data an array or object which will be transformed * @return DataResponse Reference to this object * @since 8.0.0 */ @@ -70,7 +56,7 @@ class DataResponse extends Response { /** * Used to get the set parameters - * @return array|int|float|string|bool|object the data + * @return T the data * @since 8.0.0 */ public function getData() { diff --git a/lib/public/AppFramework/Http/DownloadResponse.php b/lib/public/AppFramework/Http/DownloadResponse.php index b80f03958c0..190de022d36 100644 --- a/lib/public/AppFramework/Http/DownloadResponse.php +++ b/lib/public/AppFramework/Http/DownloadResponse.php @@ -1,43 +1,33 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; + /** * Prompts the user to download the a file * @since 7.0.0 + * @template S of Http::STATUS_* + * @template C of string + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class DownloadResponse extends Response { /** * Creates a response that prompts the user to download the file * @param string $filename the name that the downloaded file should have - * @param string $contentType the mimetype that the downloaded file should have + * @param C $contentType the mimetype that the downloaded file should have + * @param S $status + * @param H $headers * @since 7.0.0 */ - public function __construct(string $filename, string $contentType) { - parent::__construct(); + public function __construct(string $filename, string $contentType, int $status = Http::STATUS_OK, array $headers = []) { + parent::__construct($status, $headers); $filename = strtr($filename, ['"' => '\\"', '\\' => '\\\\']); diff --git a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php index 98a42aeabb5..b8bbfdb7d67 100644 --- a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php @@ -1,28 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Pavel Krasikov <klonishe@gmail.com> - * @author Pierre Rudloff <contact@rudloff.pro> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Citharel <nextcloud@tcit.fr> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -37,23 +18,25 @@ namespace OCP\AppFramework\Http; * @since 9.0.0 */ class EmptyContentSecurityPolicy { - /** @var bool Whether inline JS snippets are allowed */ - protected $inlineScriptAllowed = null; - /** @var string Whether JS nonces should be used */ - protected $useJsNonce = null; + /** @var ?string JS nonce to be used */ + protected ?string $jsNonce = null; /** @var bool Whether strict-dynamic should be used */ protected $strictDynamicAllowed = null; + /** @var bool Whether strict-dynamic should be used on script-src-elem */ + protected $strictDynamicAllowedOnScripts = null; /** * @var bool Whether eval in JS scripts is allowed - * TODO: Disallow per default + * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/11925 */ protected $evalScriptAllowed = null; + /** @var bool Whether WebAssembly compilation is allowed */ + protected ?bool $evalWasmAllowed = null; /** @var array Domains from which scripts can get loaded */ protected $allowedScriptDomains = null; /** * @var bool Whether inline CSS is allowed - * TODO: Disallow per default + * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/13458 */ protected $inlineStyleAllowed = null; @@ -84,29 +67,29 @@ class EmptyContentSecurityPolicy { protected $reportTo = null; /** - * Whether inline JavaScript snippets are allowed or forbidden * @param bool $state - * @return $this - * @since 8.1.0 - * @deprecated 10.0 CSP tokens are now used + * @return EmptyContentSecurityPolicy + * @since 24.0.0 */ - public function allowInlineScript($state = false) { - $this->inlineScriptAllowed = $state; + public function useStrictDynamic(bool $state = false): self { + $this->strictDynamicAllowed = $state; return $this; } /** + * In contrast to `useStrictDynamic` this only sets strict-dynamic on script-src-elem + * Meaning only grants trust to all imports of scripts that were loaded in `<script>` tags, and thus weakens less the CSP. * @param bool $state * @return EmptyContentSecurityPolicy - * @since 24.0.0 + * @since 28.0.0 */ - public function useStrictDynamic(bool $state = false): self { - $this->strictDynamicAllowed = $state; + public function useStrictDynamicOnScripts(bool $state = false): self { + $this->strictDynamicAllowedOnScripts = $state; return $this; } /** - * Use the according JS nonce + * The base64 encoded nonce to be used for script source. * This method is only for CSPMiddleware, custom values are ignored in mergePolicies of ContentSecurityPolicyManager * * @param string $nonce @@ -114,7 +97,7 @@ class EmptyContentSecurityPolicy { * @since 11.0.0 */ public function useJsNonce($nonce) { - $this->useJsNonce = $nonce; + $this->jsNonce = $nonce; return $this; } @@ -123,7 +106,7 @@ class EmptyContentSecurityPolicy { * @param bool $state * @return $this * @since 8.1.0 - * @deprecated Eval should not be used anymore. Please update your scripts. This function will stop functioning in a future version of Nextcloud. + * @deprecated 17.0.0 Eval should not be used anymore. Please update your scripts. This function will stop functioning in a future version of Nextcloud. */ public function allowEvalScript($state = true) { $this->evalScriptAllowed = $state; @@ -131,6 +114,17 @@ class EmptyContentSecurityPolicy { } /** + * Whether WebAssembly compilation is allowed or forbidden + * @param bool $state + * @return $this + * @since 28.0.0 + */ + public function allowEvalWasm(bool $state = true) { + $this->evalWasmAllowed = $state; + return $this; + } + + /** * Allows to execute JavaScript files from a specific domain. Use * to * allow JavaScript from all domains. * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. @@ -447,29 +441,37 @@ class EmptyContentSecurityPolicy { $policy .= "base-uri 'none';"; $policy .= "manifest-src 'self';"; - if (!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) { + if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed || $this->evalWasmAllowed || is_string($this->jsNonce)) { $policy .= 'script-src '; - if (is_string($this->useJsNonce)) { + $scriptSrc = ''; + if (is_string($this->jsNonce)) { if ($this->strictDynamicAllowed) { - $policy .= '\'strict-dynamic\' '; + $scriptSrc .= '\'strict-dynamic\' '; } - $policy .= '\'nonce-'.base64_encode($this->useJsNonce).'\''; + $scriptSrc .= '\'nonce-' . $this->jsNonce . '\''; $allowedScriptDomains = array_flip($this->allowedScriptDomains); unset($allowedScriptDomains['\'self\'']); $this->allowedScriptDomains = array_flip($allowedScriptDomains); if (count($allowedScriptDomains) !== 0) { - $policy .= ' '; + $scriptSrc .= ' '; } } if (is_array($this->allowedScriptDomains)) { - $policy .= implode(' ', $this->allowedScriptDomains); - } - if ($this->inlineScriptAllowed) { - $policy .= ' \'unsafe-inline\''; + $scriptSrc .= implode(' ', $this->allowedScriptDomains); } if ($this->evalScriptAllowed) { - $policy .= ' \'unsafe-eval\''; + $scriptSrc .= ' \'unsafe-eval\''; } + if ($this->evalWasmAllowed) { + $scriptSrc .= ' \'wasm-unsafe-eval\''; + } + $policy .= $scriptSrc . ';'; + } + + // We only need to set this if 'strictDynamicAllowed' is not set because otherwise we can simply fall back to script-src + if ($this->strictDynamicAllowedOnScripts && is_string($this->jsNonce) && !$this->strictDynamicAllowed) { + $policy .= 'script-src-elem \'strict-dynamic\' '; + $policy .= $scriptSrc ?? ''; $policy .= ';'; } diff --git a/lib/public/AppFramework/Http/EmptyFeaturePolicy.php b/lib/public/AppFramework/Http/EmptyFeaturePolicy.php index b73eaf667e7..a1d19a9f34b 100644 --- a/lib/public/AppFramework/Http/EmptyFeaturePolicy.php +++ b/lib/public/AppFramework/Http/EmptyFeaturePolicy.php @@ -1,27 +1,9 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; diff --git a/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php b/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php new file mode 100644 index 00000000000..b724b3a72ad --- /dev/null +++ b/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCP\AppFramework\Http\Events; + +use OCP\AppFramework\Http\TemplateResponse; +use OCP\EventDispatcher\Event; + +/** + * Emitted before the rendering step of the login TemplateResponse. + * + * @since 28.0.0 + */ +class BeforeLoginTemplateRenderedEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct( + private TemplateResponse $response, + ) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getResponse(): TemplateResponse { + return $this->response; + } +} diff --git a/lib/public/AppFramework/Http/Events/BeforeTemplateRenderedEvent.php b/lib/public/AppFramework/Http/Events/BeforeTemplateRenderedEvent.php index 65549eaf8df..7219ca5bfb6 100644 --- a/lib/public/AppFramework/Http/Events/BeforeTemplateRenderedEvent.php +++ b/lib/public/AppFramework/Http/Events/BeforeTemplateRenderedEvent.php @@ -3,27 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Julius Härtl <jus@bitgrid.net> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Events; diff --git a/lib/public/AppFramework/Http/FeaturePolicy.php b/lib/public/AppFramework/Http/FeaturePolicy.php index d193dda546b..2291a78055c 100644 --- a/lib/public/AppFramework/Http/FeaturePolicy.php +++ b/lib/public/AppFramework/Http/FeaturePolicy.php @@ -1,27 +1,9 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; diff --git a/lib/public/AppFramework/Http/FileDisplayResponse.php b/lib/public/AppFramework/Http/FileDisplayResponse.php index 41b452b5553..c18404b7d91 100644 --- a/lib/public/AppFramework/Http/FileDisplayResponse.php +++ b/lib/public/AppFramework/Http/FileDisplayResponse.php @@ -1,54 +1,39 @@ <?php + /** - * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; use OCP\AppFramework\Http; +use OCP\Files\File; +use OCP\Files\SimpleFS\ISimpleFile; /** * Class FileDisplayResponse * * @since 11.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class FileDisplayResponse extends Response implements ICallbackResponse { - /** @var \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile */ + /** @var File|ISimpleFile */ private $file; /** * FileDisplayResponse constructor. * - * @param \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile $file - * @param int $statusCode - * @param array $headers + * @param File|ISimpleFile $file + * @param S $statusCode + * @param H $headers * @since 11.0.0 */ - public function __construct($file, $statusCode = Http::STATUS_OK, - $headers = []) { - parent::__construct(); + public function __construct(File|ISimpleFile $file, int $statusCode = Http::STATUS_OK, array $headers = []) { + parent::__construct($statusCode, $headers); $this->file = $file; - $this->setStatus($statusCode); - $this->setHeaders(array_merge($this->getHeaders(), $headers)); $this->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"'); $this->setETag($file->getEtag()); diff --git a/lib/public/AppFramework/Http/ICallbackResponse.php b/lib/public/AppFramework/Http/ICallbackResponse.php index e0948769d94..a51f72612fb 100644 --- a/lib/public/AppFramework/Http/ICallbackResponse.php +++ b/lib/public/AppFramework/Http/ICallbackResponse.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; diff --git a/lib/public/AppFramework/Http/IOutput.php b/lib/public/AppFramework/Http/IOutput.php index 33f13503d27..105eaa0edb9 100644 --- a/lib/public/AppFramework/Http/IOutput.php +++ b/lib/public/AppFramework/Http/IOutput.php @@ -1,28 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Stefan Weil <sw@weilnetz.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; diff --git a/lib/public/AppFramework/Http/JSONResponse.php b/lib/public/AppFramework/Http/JSONResponse.php index d31a2761673..a226e29a1b5 100644 --- a/lib/public/AppFramework/Http/JSONResponse.php +++ b/lib/public/AppFramework/Http/JSONResponse.php @@ -1,29 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -32,26 +12,43 @@ use OCP\AppFramework\Http; /** * A renderer for JSON calls * @since 6.0.0 + * @template S of Http::STATUS_* + * @template-covariant T of null|string|int|float|bool|array|\stdClass|\JsonSerializable + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class JSONResponse extends Response { /** * response data - * @var array|object + * @var T */ protected $data; + /** + * Additional `json_encode` flags + * @var int + */ + protected $encodeFlags; /** * constructor of JSONResponse - * @param array|object $data the object or array that should be transformed - * @param int $statusCode the Http status code, defaults to 200 + * @param T $data the object or array that should be transformed + * @param S $statusCode the Http status code, defaults to 200 + * @param H $headers + * @param int $encodeFlags Additional `json_encode` flags * @since 6.0.0 + * @since 30.0.0 Added `$encodeFlags` param */ - public function __construct($data = [], $statusCode = Http::STATUS_OK) { - parent::__construct(); + public function __construct( + mixed $data = [], + int $statusCode = Http::STATUS_OK, + array $headers = [], + int $encodeFlags = 0, + ) { + parent::__construct($statusCode, $headers); $this->data = $data; - $this->setStatus($statusCode); + $this->encodeFlags = $encodeFlags; $this->addHeader('Content-Type', 'application/json; charset=utf-8'); } @@ -61,15 +58,19 @@ class JSONResponse extends Response { * @return string the rendered json * @since 6.0.0 * @throws \Exception If data could not get encoded + * + * @psalm-taint-escape has_quotes + * @psalm-taint-escape html */ public function render() { - return json_encode($this->data, JSON_HEX_TAG | JSON_THROW_ON_ERROR); + return json_encode($this->data, JSON_HEX_TAG | JSON_THROW_ON_ERROR | $this->encodeFlags, 2048); } /** * Sets values in the data json array - * @param array|object $data an array or object which will be transformed - * to JSON + * @psalm-suppress InvalidTemplateParam + * @param T $data an array or object which will be transformed + * to JSON * @return JSONResponse Reference to this object * @since 6.0.0 - return value was added in 7.0.0 */ @@ -81,8 +82,7 @@ class JSONResponse extends Response { /** - * Used to get the set parameters - * @return array the data + * @return T the data * @since 6.0.0 */ public function getData() { diff --git a/lib/public/AppFramework/Http/NotFoundResponse.php b/lib/public/AppFramework/Http/NotFoundResponse.php index 34b74d353db..137d1a26655 100644 --- a/lib/public/AppFramework/Http/NotFoundResponse.php +++ b/lib/public/AppFramework/Http/NotFoundResponse.php @@ -1,41 +1,30 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Julius Härtl <jus@bitgrid.net> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; + /** * A generic 404 response showing an 404 error page as well to the end-user * @since 8.1.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends TemplateResponse<Http::STATUS_*, array<string, mixed>> */ class NotFoundResponse extends TemplateResponse { /** + * @param S $status + * @param H $headers * @since 8.1.0 */ - public function __construct() { - parent::__construct('core', '404', [], 'guest'); + public function __construct(int $status = Http::STATUS_NOT_FOUND, array $headers = []) { + parent::__construct('core', '404', [], 'guest', $status, $headers); $this->setContentSecurityPolicy(new ContentSecurityPolicy()); - $this->setStatus(404); } } diff --git a/lib/public/AppFramework/Http/ParameterOutOfRangeException.php b/lib/public/AppFramework/Http/ParameterOutOfRangeException.php new file mode 100644 index 00000000000..3286917d4d0 --- /dev/null +++ b/lib/public/AppFramework/Http/ParameterOutOfRangeException.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http; + +/** + * @since 29.0.0 + */ +class ParameterOutOfRangeException extends \OutOfRangeException { + /** + * @since 29.0.0 + */ + public function __construct( + protected string $parameterName, + protected int $actualValue, + protected int $minValue, + protected int $maxValue, + ) { + parent::__construct( + sprintf( + 'Parameter %s must be between %d and %d', + $this->parameterName, + $this->minValue, + $this->maxValue, + ) + ); + } + + /** + * @since 29.0.0 + */ + public function getParameterName(): string { + return $this->parameterName; + } + + /** + * @since 29.0.0 + */ + public function getActualValue(): int { + return $this->actualValue; + } + + /** + * @since 29.0.0 + */ + public function getMinValue(): int { + return $this->minValue; + } + + /** + * @since 29.0.0 + */ + public function getMaxValue(): int { + return $this->maxValue; + } +} diff --git a/lib/public/AppFramework/Http/RedirectResponse.php b/lib/public/AppFramework/Http/RedirectResponse.php index 87853391e86..74847205976 100644 --- a/lib/public/AppFramework/Http/RedirectResponse.php +++ b/lib/public/AppFramework/Http/RedirectResponse.php @@ -1,27 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author v1r0x <vinzenz.rosenkranz@gmail.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -30,6 +12,9 @@ use OCP\AppFramework\Http; /** * Redirects to a different URL * @since 7.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class RedirectResponse extends Response { private $redirectURL; @@ -37,13 +22,14 @@ class RedirectResponse extends Response { /** * Creates a response that redirects to a url * @param string $redirectURL the url to redirect to + * @param S $status + * @param H $headers * @since 7.0.0 */ - public function __construct($redirectURL) { - parent::__construct(); + public function __construct(string $redirectURL, int $status = Http::STATUS_SEE_OTHER, array $headers = []) { + parent::__construct($status, $headers); $this->redirectURL = $redirectURL; - $this->setStatus(Http::STATUS_SEE_OTHER); $this->addHeader('Location', $redirectURL); } diff --git a/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php b/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php index ad11b53637b..0a0c04f671d 100644 --- a/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php +++ b/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php @@ -3,29 +3,12 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com> - * - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; use OCP\IURLGenerator; /** @@ -33,17 +16,21 @@ use OCP\IURLGenerator; * * @since 16.0.0 * @deprecated 23.0.0 Use RedirectResponse() with IURLGenerator::linkToDefaultPageUrl() instead + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends RedirectResponse<Http::STATUS_*, array<string, mixed>> */ class RedirectToDefaultAppResponse extends RedirectResponse { /** * Creates a response that redirects to the default app * + * @param S $status + * @param H $headers * @since 16.0.0 * @deprecated 23.0.0 Use RedirectResponse() with IURLGenerator::linkToDefaultPageUrl() instead */ - public function __construct() { - /** @var IURLGenerator $urlGenerator */ - $urlGenerator = \OC::$server->get(IURLGenerator::class); - parent::__construct($urlGenerator->linkToDefaultPageUrl()); + public function __construct(int $status = Http::STATUS_SEE_OTHER, array $headers = []) { + $urlGenerator = \OCP\Server::get(IURLGenerator::class); + parent::__construct($urlGenerator->linkToDefaultPageUrl(), $status, $headers); } } diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php index 4db6caa556c..bdebb12c00d 100644 --- a/lib/public/AppFramework/Http/Response.php +++ b/lib/public/AppFramework/Http/Response.php @@ -1,32 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Clement Wong <git@clement.hk> - * @author Joas Schilling <coding@schilljs.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -41,15 +18,15 @@ use Psr\Log\LoggerInterface; * * It handles headers, HTTP status code, last modified and ETag. * @since 6.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> */ class Response { /** - * Headers - defaults to ['Cache-Control' => 'no-cache, no-store, must-revalidate'] - * @var array + * Headers + * @var H */ - private $headers = [ - 'Cache-Control' => 'no-cache, no-store, must-revalidate' - ]; + private $headers; /** @@ -61,9 +38,9 @@ class Response { /** * HTTP status code - defaults to STATUS OK - * @var int + * @var S */ - private $status = Http::STATUS_OK; + private $status; /** @@ -91,15 +68,13 @@ class Response { private $throttleMetadata = []; /** + * @param S $status + * @param H $headers * @since 17.0.0 */ - public function __construct() { - /** @var IRequest $request */ - /** - * @psalm-suppress UndefinedClass - */ - $request = \OC::$server->get(IRequest::class); - $this->addHeader("X-Request-Id", $request->getId()); + public function __construct(int $status = Http::STATUS_OK, array $headers = []) { + $this->setStatus($status); + $this->setHeaders($headers); } /** @@ -113,20 +88,18 @@ class Response { */ public function cacheFor(int $cacheSeconds, bool $public = false, bool $immutable = false) { if ($cacheSeconds > 0) { - $pragma = $public ? 'public' : 'private'; - $this->addHeader('Cache-Control', sprintf('%s, max-age=%s, %s', $pragma, $cacheSeconds, ($immutable ? 'immutable' : 'must-revalidate'))); - $this->addHeader('Pragma', $pragma); + $cacheStore = $public ? 'public' : 'private'; + $this->addHeader('Cache-Control', sprintf('%s, max-age=%s, %s', $cacheStore, $cacheSeconds, ($immutable ? 'immutable' : 'must-revalidate'))); // Set expires header $expires = new \DateTime(); - /** @var ITimeFactory $time */ - $time = \OC::$server->query(ITimeFactory::class); + $time = \OCP\Server::get(ITimeFactory::class); $expires->setTimestamp($time->getTime()); - $expires->add(new \DateInterval('PT'.$cacheSeconds.'S')); - $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC2822)); + $expires->add(new \DateInterval('PT' . $cacheSeconds . 'S')); + $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC7231)); } else { $this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); - unset($this->headers['Expires'], $this->headers['Pragma']); + unset($this->headers['Expires']); } return $this; @@ -137,13 +110,13 @@ class Response { * @param string $name The name of the cookie * @param string $value The value of the cookie * @param \DateTime|null $expireDate Date on that the cookie should expire, if set - * to null cookie will be considered as session - * cookie. + * to null cookie will be considered as session + * cookie. * @param string $sameSite The samesite value of the cookie. Defaults to Lax. Other possibilities are Strict or None * @return $this * @since 8.0.0 */ - public function addCookie($name, $value, \DateTime $expireDate = null, $sameSite = 'Lax') { + public function addCookie($name, $value, ?\DateTime $expireDate = null, $sameSite = 'Lax') { $this->cookies[$name] = ['value' => $value, 'expireDate' => $expireDate, 'sameSite' => $sameSite]; return $this; } @@ -210,10 +183,10 @@ class Response { if ($this->status === Http::STATUS_NOT_MODIFIED && stripos($name, 'x-') === 0) { /** @var IConfig $config */ - $config = \OC::$server->get(IConfig::class); + $config = \OCP\Server::get(IConfig::class); if ($config->getSystemValueBool('debug', false)) { - \OC::$server->get(LoggerInterface::class)->error('Setting custom header on a 204 or 304 is not supported (Header: {header})', [ + \OCP\Server::get(LoggerInterface::class)->error('Setting custom header on a 304 is not supported (Header: {header})', [ 'header' => $name, ]); } @@ -231,11 +204,14 @@ class Response { /** * Set the headers - * @param array $headers value header pairs - * @return $this + * @template NewH as array<string, mixed> + * @param NewH $headers value header pairs + * @psalm-this-out static<S, NewH> + * @return static * @since 8.0.0 */ - public function setHeaders(array $headers) { + public function setHeaders(array $headers): static { + /** @psalm-suppress InvalidPropertyAssignmentValue Expected due to @psalm-this-out */ $this->headers = $headers; return $this; @@ -244,21 +220,27 @@ class Response { /** * Returns the set headers - * @return array the headers + * @return array{X-Request-Id: string, Cache-Control: string, Content-Security-Policy: string, Feature-Policy: string, X-Robots-Tag: string, Last-Modified?: string, ETag?: string, ...H} the headers * @since 6.0.0 */ public function getHeaders() { - $mergeWith = []; + /** @var IRequest $request */ + /** + * @psalm-suppress UndefinedClass + */ + $request = \OCP\Server::get(IRequest::class); + $mergeWith = [ + 'X-Request-Id' => $request->getId(), + 'Cache-Control' => 'no-cache, no-store, must-revalidate', + 'Content-Security-Policy' => $this->getContentSecurityPolicy()->buildPolicy(), + 'Feature-Policy' => $this->getFeaturePolicy()->buildPolicy(), + 'X-Robots-Tag' => 'noindex, nofollow', + ]; if ($this->lastModified) { - $mergeWith['Last-Modified'] = - $this->lastModified->format(\DateTimeInterface::RFC2822); + $mergeWith['Last-Modified'] = $this->lastModified->format(\DateTimeInterface::RFC7231); } - $this->headers['Content-Security-Policy'] = $this->getContentSecurityPolicy()->buildPolicy(); - $this->headers['Feature-Policy'] = $this->getFeaturePolicy()->buildPolicy(); - $this->headers['X-Robots-Tag'] = 'none'; - if ($this->ETag) { $mergeWith['ETag'] = '"' . $this->ETag . '"'; } @@ -279,11 +261,14 @@ class Response { /** * Set response status - * @param int $status a HTTP status code, see also the STATUS constants - * @return Response Reference to this object + * @template NewS as int + * @param NewS $status a HTTP status code, see also the STATUS constants + * @psalm-this-out static<NewS, H> + * @return static * @since 6.0.0 - return value was added in 7.0.0 */ - public function setStatus($status) { + public function setStatus($status): static { + /** @psalm-suppress InvalidPropertyAssignmentValue Expected due to @psalm-this-out */ $this->status = $status; return $this; @@ -303,7 +288,7 @@ class Response { /** * Get the currently used Content-Security-Policy * @return EmptyContentSecurityPolicy|null Used Content-Security-Policy or null if - * none specified. + * none specified. * @since 8.1.0 */ public function getContentSecurityPolicy() { @@ -338,6 +323,7 @@ class Response { /** * Get response status * @since 6.0.0 + * @return S */ public function getStatus() { return $this->status; diff --git a/lib/public/AppFramework/Http/StandaloneTemplateResponse.php b/lib/public/AppFramework/Http/StandaloneTemplateResponse.php index 35a48481333..244a6b80f9f 100644 --- a/lib/public/AppFramework/Http/StandaloneTemplateResponse.php +++ b/lib/public/AppFramework/Http/StandaloneTemplateResponse.php @@ -1,30 +1,14 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; + /** * A template response that does not emit the loadAdditionalScripts events. * @@ -32,6 +16,9 @@ namespace OCP\AppFramework\Http; * full nextcloud UI. Like the 2FA page, or the grant page in the login flow. * * @since 16.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends TemplateResponse<Http::STATUS_*, array<string, mixed>> */ class StandaloneTemplateResponse extends TemplateResponse { } diff --git a/lib/public/AppFramework/Http/StreamResponse.php b/lib/public/AppFramework/Http/StreamResponse.php index 25ad37e5d9a..d0e6e3e148a 100644 --- a/lib/public/AppFramework/Http/StreamResponse.php +++ b/lib/public/AppFramework/Http/StreamResponse.php @@ -1,28 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Http; @@ -32,6 +13,9 @@ use OCP\AppFramework\Http; * Class StreamResponse * * @since 8.1.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class StreamResponse extends Response implements ICallbackResponse { /** @var string */ @@ -39,10 +23,12 @@ class StreamResponse extends Response implements ICallbackResponse { /** * @param string|resource $filePath the path to the file or a file handle which should be streamed + * @param S $status + * @param H $headers * @since 8.1.0 */ - public function __construct($filePath) { - parent::__construct(); + public function __construct(mixed $filePath, int $status = Http::STATUS_OK, array $headers = []) { + parent::__construct($status, $headers); $this->filePath = $filePath; } diff --git a/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php b/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php index c62f79e8801..4b074331fc8 100644 --- a/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php @@ -1,27 +1,9 @@ <?php declare(strict_types=1); - /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; @@ -32,7 +14,7 @@ namespace OCP\AppFramework\Http; * ('self') are allowed. * * Even if a value gets modified above defaults will still get appended. Please - * notice that Nextcloud ships already with sensible defaults and those policies + * note that Nextcloud ships already with sensible defaults and those policies * should require no modification at all for most use-cases. * * This class represents out strictest defaults. They may get change from release @@ -46,6 +28,8 @@ class StrictContentSecurityPolicy extends EmptyContentSecurityPolicy { protected $inlineScriptAllowed = false; /** @var bool Whether eval in JS scripts is allowed */ protected $evalScriptAllowed = false; + /** @var bool Whether WebAssembly compilation is allowed */ + protected ?bool $evalWasmAllowed = false; /** @var array Domains from which scripts can get loaded */ protected $allowedScriptDomains = [ '\'self\'', diff --git a/lib/public/AppFramework/Http/StrictEvalContentSecurityPolicy.php b/lib/public/AppFramework/Http/StrictEvalContentSecurityPolicy.php index ed799e4fd94..b59dd0fcce7 100644 --- a/lib/public/AppFramework/Http/StrictEvalContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/StrictEvalContentSecurityPolicy.php @@ -1,38 +1,20 @@ <?php declare(strict_types=1); - /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; /** - * Class StrictInlineContentSecurityPolicy is a simple helper which allows applications to + * Class StrictEvalContentSecurityPolicy is a simple helper which allows applications to * modify the Content-Security-Policy sent by Nextcloud. Per default only JavaScript, * stylesheets, images, fonts, media and connections from the same domain * ('self') are allowed. * * Even if a value gets modified above defaults will still get appended. Please - * notice that Nextcloud ships already with sensible defaults and those policies + * note that Nextcloud ships already with sensible defaults and those policies * should require no modification at all for most use-cases. * * This is a temp helper class from the default ContentSecurityPolicy to allow slow diff --git a/lib/public/AppFramework/Http/StrictInlineContentSecurityPolicy.php b/lib/public/AppFramework/Http/StrictInlineContentSecurityPolicy.php index 45b230ad9b5..e80d37c74cf 100644 --- a/lib/public/AppFramework/Http/StrictInlineContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/StrictInlineContentSecurityPolicy.php @@ -1,27 +1,9 @@ <?php declare(strict_types=1); - /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; @@ -32,7 +14,7 @@ namespace OCP\AppFramework\Http; * ('self') are allowed. * * Even if a value gets modified above defaults will still get appended. Please - * notice that Nextcloud ships already with sensible defaults and those policies + * note that Nextcloud ships already with sensible defaults and those policies * should require no modification at all for most use-cases. * * This is a temp helper class from the default ContentSecurityPolicy to allow slow diff --git a/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php b/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php index e5b09193ba9..281bb559a10 100644 --- a/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php +++ b/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php @@ -1,78 +1,29 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Daniel Calviño Sánchez <danxuliu@gmail.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; -use OCP\Util; - /** * Class LinkMenuAction * * @since 14.0.0 */ class ExternalShareMenuAction extends SimpleMenuAction { - /** @var string */ - private $owner; - - /** @var string */ - private $displayname; - - /** @var string */ - private $shareName; /** * ExternalShareMenuAction constructor. * - * @param string $label - * @param string $icon - * @param string $owner - * @param string $displayname - * @param string $shareName + * @param string $label Translated label + * @param string $icon Icon CSS class + * @param string $owner Owner user ID (unused) + * @param string $displayname Display name of the owner (unused) + * @param string $shareName Name of the share (unused) * @since 14.0.0 */ public function __construct(string $label, string $icon, string $owner, string $displayname, string $shareName) { parent::__construct('save', $label, $icon); - $this->owner = $owner; - $this->displayname = $displayname; - $this->shareName = $shareName; - } - - /** - * @since 14.0.0 - */ - public function render(): string { - return '<li>' . - ' <button id="save-external-share" class="icon ' . Util::sanitizeHTML($this->getIcon()) . '" data-protected="false" data-owner-display-name="' . Util::sanitizeHTML($this->displayname) . '" data-owner="' . Util::sanitizeHTML($this->owner) . '" data-name="' . Util::sanitizeHTML($this->shareName) . '">' . Util::sanitizeHTML($this->getLabel()) . '</button>' . - '</li>' . - '<li id="external-share-menu-item" class="hidden">' . - ' <span class="menuitem">' . - ' <form class="save-form" action="#">' . - ' <input type="text" id="remote_address" placeholder="user@yourNextcloud.org">' . - ' <input type="submit" value=" " id="save-button-confirm" class="icon-confirm" disabled="disabled"></button>' . - ' </form>' . - ' </span>' . - '</li>'; } } diff --git a/lib/public/AppFramework/Http/Template/IMenuAction.php b/lib/public/AppFramework/Http/Template/IMenuAction.php index 83e52bd882f..124e95fe019 100644 --- a/lib/public/AppFramework/Http/Template/IMenuAction.php +++ b/lib/public/AppFramework/Http/Template/IMenuAction.php @@ -1,25 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; @@ -36,12 +19,16 @@ interface IMenuAction { public function getId(): string; /** + * The translated label of the menu item. + * * @since 14.0.0 * @return string */ public function getLabel(): string; /** + * The link this menu item points to. + * * @since 14.0.0 * @return string */ @@ -54,6 +41,9 @@ interface IMenuAction { public function getPriority(): int; /** + * Custom render function. + * The returned HTML will be wrapped within a listitem element (`<li>...</li>`). + * * @since 14.0.0 * @return string */ diff --git a/lib/public/AppFramework/Http/Template/LinkMenuAction.php b/lib/public/AppFramework/Http/Template/LinkMenuAction.php index 4982172bffe..391802a1dce 100644 --- a/lib/public/AppFramework/Http/Template/LinkMenuAction.php +++ b/lib/public/AppFramework/Http/Template/LinkMenuAction.php @@ -1,30 +1,11 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Julius Härtl <jus@bitgrid.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; -use OCP\Util; - /** * Class LinkMenuAction * @@ -40,24 +21,6 @@ class LinkMenuAction extends SimpleMenuAction { * @since 14.0.0 */ public function __construct(string $label, string $icon, string $link) { - parent::__construct('directLink-container', $label, $icon, $link); - } - - /** - * @return string - * @since 14.0.0 - */ - public function render(): string { - return '<li>' . - '<a id="directLink-container">' . - '<span class="icon ' . Util::sanitizeHTML($this->getIcon()) . '"></span>' . - '<label for="directLink">' . Util::sanitizeHTML($this->getLabel()) . '</label>' . - '</a>' . - '</li>' . - '<li>' . - '<span class="menuitem">' . - '<input id="directLink" type="text" readonly="" value="' . Util::sanitizeHTML($this->getLink()) . '">' . - '</span>' . - '</li>'; + parent::__construct('directLink', $label, $icon, $link); } } diff --git a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php index 1196c90935d..4c156cdecea 100644 --- a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php +++ b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php @@ -1,40 +1,28 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Julius Härtl <jus@bitgrid.net> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; use InvalidArgumentException; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\TemplateResponse; +use OCP\IInitialStateService; /** * Class PublicTemplateResponse * * @since 14.0.0 + * @template H of array<string, mixed> + * @template S of Http::STATUS_* + * @template-extends TemplateResponse<Http::STATUS_*, array<string, mixed>> */ class PublicTemplateResponse extends TemplateResponse { private $headerTitle = ''; private $headerDetails = ''; + /** @var IMenuAction[] */ private $headerActions = []; private $footerVisible = true; @@ -44,11 +32,43 @@ class PublicTemplateResponse extends TemplateResponse { * @param string $appName * @param string $templateName * @param array $params + * @param S $status + * @param H $headers * @since 14.0.0 */ - public function __construct(string $appName, string $templateName, array $params = []) { - parent::__construct($appName, $templateName, $params, 'public'); - \OC_Util::addScript('core', 'public/publicpage'); + public function __construct( + string $appName, + string $templateName, + array $params = [], + $status = Http::STATUS_OK, + array $headers = [], + ) { + parent::__construct($appName, $templateName, $params, 'public', $status, $headers); + \OCP\Util::addScript('core', 'public-page-menu'); + \OCP\Util::addScript('core', 'public-page-user-menu'); + + $state = \OCP\Server::get(IInitialStateService::class); + $state->provideLazyInitialState('core', 'public-page-menu', function () { + $response = []; + foreach ($this->headerActions as $action) { + // First try in it is a custom action that provides rendered HTML + $rendered = $action->render(); + if ($rendered === '') { + // If simple action, add the response data + if ($action instanceof SimpleMenuAction) { + $response[] = $action->getData(); + } + } else { + // custom action so add the rendered output + $response[] = [ + 'id' => $action->getId(), + 'label' => $action->getLabel(), + 'html' => $rendered, + ]; + } + } + return $response; + }); } /** @@ -151,6 +171,6 @@ class PublicTemplateResponse extends TemplateResponse { 'template' => $this, ]); $this->setParams($params); - return parent::render(); + return parent::render(); } } diff --git a/lib/public/AppFramework/Http/Template/SimpleMenuAction.php b/lib/public/AppFramework/Http/Template/SimpleMenuAction.php index de13f3ef0b2..03cb9b4c7ea 100644 --- a/lib/public/AppFramework/Http/Template/SimpleMenuAction.php +++ b/lib/public/AppFramework/Http/Template/SimpleMenuAction.php @@ -1,30 +1,11 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; -use OCP\Util; - /** * Class SimpleMenuAction * @@ -86,6 +67,8 @@ class SimpleMenuAction implements IMenuAction { } /** + * The icon CSS class to use. + * * @return string * @since 14.0.0 */ @@ -110,14 +93,28 @@ class SimpleMenuAction implements IMenuAction { } /** + * Custom render function. + * The returned HTML must be wrapped within a listitem (`<li>...</li>`). + * * If an empty string is returned, the default design is used (based on the label and link specified). * @return string * @since 14.0.0 */ public function render(): string { - $detailContent = ($this->detail !== '') ? ' <span class="download-size">(' . Util::sanitizeHTML($this->detail) . ')</span>' : ''; - return sprintf( - '<li id="%s"><a href="%s"><span class="icon %s"></span>%s %s</a></li>', - Util::sanitizeHTML($this->id), Util::sanitizeHTML($this->link), Util::sanitizeHTML($this->icon), Util::sanitizeHTML($this->label), $detailContent - ); + return ''; + } + + /** + * Return JSON data to let the frontend render the menu entry. + * @return array{id: string, label: string, href: string, icon: string, details: string|null} + * @since 31.0.0 + */ + public function getData(): array { + return [ + 'id' => $this->id, + 'label' => $this->label, + 'href' => $this->link, + 'icon' => $this->icon, + 'details' => $this->detail, + ]; } } diff --git a/lib/public/AppFramework/Http/TemplateResponse.php b/lib/public/AppFramework/Http/TemplateResponse.php index 23843cd21d1..af37a1a2313 100644 --- a/lib/public/AppFramework/Http/TemplateResponse.php +++ b/lib/public/AppFramework/Http/TemplateResponse.php @@ -1,36 +1,27 @@ <?php + +declare(strict_types=1); + + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; +use OCP\Server; +use OCP\Template\ITemplateManager; + /** * Response for a normal template * @since 6.0.0 + * + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class TemplateResponse extends Response { /** @@ -59,15 +50,6 @@ class TemplateResponse extends Response { public const RENDER_AS_PUBLIC = 'public'; /** - * @deprecated 20.0.0 use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent - */ - public const EVENT_LOAD_ADDITIONAL_SCRIPTS = self::class . '::loadAdditionalScripts'; - /** - * @deprecated 20.0.0 use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent - */ - public const EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN = self::class . '::loadAdditionalScriptsLoggedIn'; - - /** * name of the template * @var string */ @@ -96,13 +78,14 @@ class TemplateResponse extends Response { * @param string $appName the name of the app to load the template from * @param string $templateName the name of the template * @param array $params an array of parameters which should be passed to the - * template + * template * @param string $renderAs how the page should be rendered, defaults to user + * @param S $status + * @param H $headers * @since 6.0.0 - parameters $params and $renderAs were added in 7.0.0 */ - public function __construct($appName, $templateName, array $params = [], - $renderAs = self::RENDER_AS_USER) { - parent::__construct(); + public function __construct(string $appName, string $templateName, array $params = [], string $renderAs = self::RENDER_AS_USER, int $status = Http::STATUS_OK, array $headers = []) { + parent::__construct($status, $headers); $this->templateName = $templateName; $this->appName = $appName; @@ -203,8 +186,7 @@ class TemplateResponse extends Response { $renderAs = $this->renderAs; } - \OCP\Util::addHeader('meta', ['name' => 'robots', 'content' => 'noindex, nofollow']); - $template = new \OCP\Template($this->appName, $this->templateName, $renderAs); + $template = Server::get(ITemplateManager::class)->getTemplate($this->appName, $this->templateName, $renderAs); foreach ($this->params as $key => $value) { $template->assign($key, $value); diff --git a/lib/public/AppFramework/Http/TextPlainResponse.php b/lib/public/AppFramework/Http/TextPlainResponse.php index 93edf704863..9dfa2c5544d 100644 --- a/lib/public/AppFramework/Http/TextPlainResponse.php +++ b/lib/public/AppFramework/Http/TextPlainResponse.php @@ -1,28 +1,10 @@ <?php declare(strict_types=1); - /** - * @copyright 2021 Lukas Reschke <lukas@statuscode.ch> - * - * @author 2021 Lukas Reschke <lukas@statuscode.ch> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCP\AppFramework\Http; use OCP\AppFramework\Http; @@ -30,6 +12,9 @@ use OCP\AppFramework\Http; /** * A renderer for text responses * @since 22.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class TextPlainResponse extends Response { /** @var string */ @@ -38,14 +23,14 @@ class TextPlainResponse extends Response { /** * constructor of TextPlainResponse * @param string $text The text body - * @param int $statusCode the Http status code, defaults to 200 + * @param S $statusCode the Http status code, defaults to 200 + * @param H $headers * @since 22.0.0 */ - public function __construct(string $text = '', int $statusCode = Http::STATUS_OK) { - parent::__construct(); + public function __construct(string $text = '', int $statusCode = Http::STATUS_OK, array $headers = []) { + parent::__construct($statusCode, $headers); $this->text = $text; - $this->setStatus($statusCode); $this->addHeader('Content-Type', 'text/plain'); } diff --git a/lib/public/AppFramework/Http/TooManyRequestsResponse.php b/lib/public/AppFramework/Http/TooManyRequestsResponse.php index caf565ee954..f7084ec768d 100644 --- a/lib/public/AppFramework/Http/TooManyRequestsResponse.php +++ b/lib/public/AppFramework/Http/TooManyRequestsResponse.php @@ -1,45 +1,33 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> - * - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; -use OCP\Template; +use OCP\AppFramework\Http; +use OCP\Server; +use OCP\Template\ITemplateManager; /** * A generic 429 response showing an 404 error page as well to the end-user * @since 19.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class TooManyRequestsResponse extends Response { /** + * @param S $status + * @param H $headers * @since 19.0.0 */ - public function __construct() { - parent::__construct(); + public function __construct(int $status = Http::STATUS_TOO_MANY_REQUESTS, array $headers = []) { + parent::__construct($status, $headers); $this->setContentSecurityPolicy(new ContentSecurityPolicy()); - $this->setStatus(429); } /** @@ -47,7 +35,7 @@ class TooManyRequestsResponse extends Response { * @since 19.0.0 */ public function render() { - $template = new Template('core', '429', 'blank'); + $template = Server::get(ITemplateManager::class)->getTemplate('core', '429', TemplateResponse::RENDER_AS_BLANK); return $template->fetchPage(); } } diff --git a/lib/public/AppFramework/Http/ZipResponse.php b/lib/public/AppFramework/Http/ZipResponse.php index 23e9f1f7a94..a552eb1294f 100644 --- a/lib/public/AppFramework/Http/ZipResponse.php +++ b/lib/public/AppFramework/Http/ZipResponse.php @@ -1,40 +1,23 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Jakob Sack <mail@jakobsack.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http; use OC\Streamer; +use OCP\AppFramework\Http; use OCP\IRequest; /** * Public library to send several files in one zip archive. * * @since 15.0.0 + * @template S of Http::STATUS_* + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class ZipResponse extends Response implements ICallbackResponse { /** @var array{internalName: string, resource: resource, size: int, time: int}[] Files to be added to the zip response */ @@ -44,10 +27,12 @@ class ZipResponse extends Response implements ICallbackResponse { private IRequest $request; /** + * @param S $status + * @param H $headers * @since 15.0.0 */ - public function __construct(IRequest $request, string $name = 'output') { - parent::__construct(); + public function __construct(IRequest $request, string $name = 'output', int $status = Http::STATUS_OK, array $headers = []) { + parent::__construct($status, $headers); $this->name = $name; $this->request = $request; diff --git a/lib/public/AppFramework/IAppContainer.php b/lib/public/AppFramework/IAppContainer.php index 355e1fd0366..c20b252b0ce 100644 --- a/lib/public/AppFramework/IAppContainer.php +++ b/lib/public/AppFramework/IAppContainer.php @@ -1,30 +1,10 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; diff --git a/lib/public/AppFramework/Middleware.php b/lib/public/AppFramework/Middleware.php index 62b5e47c4cf..33bc288780e 100644 --- a/lib/public/AppFramework/Middleware.php +++ b/lib/public/AppFramework/Middleware.php @@ -1,30 +1,13 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Stefan Weil <sw@weilnetz.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; +use Exception; use OCP\AppFramework\Http\Response; /** @@ -45,7 +28,7 @@ abstract class Middleware { * @return void * @since 6.0.0 */ - public function beforeController($controller, $methodName) { + public function beforeController(Controller $controller, string $methodName) { } @@ -59,12 +42,12 @@ abstract class Middleware { * @param Controller $controller the controller that is being called * @param string $methodName the name of the method that will be called on * the controller - * @param \Exception $exception the thrown exception - * @throws \Exception the passed in exception if it can't handle it + * @param Exception $exception the thrown exception + * @throws Exception the passed in exception if it can't handle it * @return Response a Response object in case that the exception was handled * @since 6.0.0 */ - public function afterException($controller, $methodName, \Exception $exception) { + public function afterException(Controller $controller, string $methodName, Exception $exception) { throw $exception; } @@ -80,7 +63,7 @@ abstract class Middleware { * @return Response a Response object * @since 6.0.0 */ - public function afterController($controller, $methodName, Response $response) { + public function afterController(Controller $controller, string $methodName, Response $response) { return $response; } @@ -96,7 +79,7 @@ abstract class Middleware { * @return string the output that should be printed * @since 6.0.0 */ - public function beforeOutput($controller, $methodName, $output) { + public function beforeOutput(Controller $controller, string $methodName, string $output) { return $output; } } diff --git a/lib/public/AppFramework/OCS/OCSBadRequestException.php b/lib/public/AppFramework/OCS/OCSBadRequestException.php index db146076f2a..77b8ec6c86d 100644 --- a/lib/public/AppFramework/OCS/OCSBadRequestException.php +++ b/lib/public/AppFramework/OCS/OCSBadRequestException.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\OCS; @@ -38,7 +22,7 @@ class OCSBadRequestException extends OCSException { * @param Exception|null $previous * @since 9.1.0 */ - public function __construct($message = '', Exception $previous = null) { + public function __construct($message = '', ?Exception $previous = null) { parent::__construct($message, Http::STATUS_BAD_REQUEST, $previous); } } diff --git a/lib/public/AppFramework/OCS/OCSException.php b/lib/public/AppFramework/OCS/OCSException.php index b5dfdef3571..02901992f8d 100644 --- a/lib/public/AppFramework/OCS/OCSException.php +++ b/lib/public/AppFramework/OCS/OCSException.php @@ -1,25 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\OCS; diff --git a/lib/public/AppFramework/OCS/OCSForbiddenException.php b/lib/public/AppFramework/OCS/OCSForbiddenException.php index ecdccb05a6f..0d001377043 100644 --- a/lib/public/AppFramework/OCS/OCSForbiddenException.php +++ b/lib/public/AppFramework/OCS/OCSForbiddenException.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\OCS; @@ -38,7 +22,7 @@ class OCSForbiddenException extends OCSException { * @param Exception|null $previous * @since 9.1.0 */ - public function __construct($message = '', Exception $previous = null) { + public function __construct($message = '', ?Exception $previous = null) { parent::__construct($message, Http::STATUS_FORBIDDEN, $previous); } } diff --git a/lib/public/AppFramework/OCS/OCSNotFoundException.php b/lib/public/AppFramework/OCS/OCSNotFoundException.php index 7a2ffb5de91..67cea9ed759 100644 --- a/lib/public/AppFramework/OCS/OCSNotFoundException.php +++ b/lib/public/AppFramework/OCS/OCSNotFoundException.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\OCS; @@ -38,7 +22,7 @@ class OCSNotFoundException extends OCSException { * @param Exception|null $previous * @since 9.1.0 */ - public function __construct($message = '', Exception $previous = null) { + public function __construct($message = '', ?Exception $previous = null) { parent::__construct($message, Http::STATUS_NOT_FOUND, $previous); } } diff --git a/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php b/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php new file mode 100644 index 00000000000..4fc2820eaec --- /dev/null +++ b/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php @@ -0,0 +1,28 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCP\AppFramework\OCS; + +use Exception; +use OCP\AppFramework\Http; + +/** + * Class OCSPreconditionFailedException + * + * @since 28.0.0 + */ +class OCSPreconditionFailedException extends OCSException { + /** + * OCSPreconditionFailedException constructor. + * + * @param string $message + * @param Exception|null $previous + * @since 9.1.0 + */ + public function __construct($message = '', ?Exception $previous = null) { + parent::__construct($message, Http::STATUS_PRECONDITION_FAILED, $previous); + } +} diff --git a/lib/public/AppFramework/OCSController.php b/lib/public/AppFramework/OCSController.php index 51c71ad4e64..7cde2a7e427 100644 --- a/lib/public/AppFramework/OCSController.php +++ b/lib/public/AppFramework/OCSController.php @@ -1,29 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Donquixote <marjunebatac@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Stefan Weil <sw@weilnetz.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; @@ -36,9 +16,24 @@ use OCP\IRequest; * @since 8.1.0 */ abstract class OCSController extends ApiController { + /** + * @since 22.0.0 + */ public const RESPOND_UNAUTHORISED = 997; + + /** + * @since 22.0.0 + */ public const RESPOND_SERVER_ERROR = 996; + + /** + * @since 22.0.0 + */ public const RESPOND_NOT_FOUND = 998; + + /** + * @since 22.0.0 + */ public const RESPOND_UNKNOWN_ERROR = 999; /** @var int */ @@ -49,20 +44,20 @@ abstract class OCSController extends ApiController { * @param string $appName the name of the app * @param IRequest $request an instance of the request * @param string $corsMethods comma separated string of HTTP verbs which - * should be allowed for websites or webapps when calling your API, defaults to - * 'PUT, POST, GET, DELETE, PATCH' + * should be allowed for websites or webapps when calling your API, defaults to + * 'PUT, POST, GET, DELETE, PATCH' * @param string $corsAllowedHeaders comma separated string of HTTP headers - * which should be allowed for websites or webapps when calling your API, - * defaults to 'Authorization, Content-Type, Accept' + * which should be allowed for websites or webapps when calling your API, + * defaults to 'Authorization, Content-Type, Accept' * @param int $corsMaxAge number in seconds how long a preflighted OPTIONS - * request should be cached, defaults to 1728000 seconds + * request should be cached, defaults to 1728000 seconds * @since 8.1.0 */ public function __construct($appName, - IRequest $request, - $corsMethods = 'PUT, POST, GET, DELETE, PATCH', - $corsAllowedHeaders = 'Authorization, Content-Type, Accept, OCS-APIRequest', - $corsMaxAge = 1728000) { + IRequest $request, + $corsMethods = 'PUT, POST, GET, DELETE, PATCH', + $corsAllowedHeaders = 'Authorization, Content-Type, Accept, OCS-APIRequest', + $corsMaxAge = 1728000) { parent::__construct($appName, $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge); $this->registerResponder('json', function ($data) { @@ -86,7 +81,7 @@ abstract class OCSController extends ApiController { * Since the OCS endpoints default to XML we need to find out the format * again * @param mixed $response the value that was returned from a controller and - * is not a Response instance + * is not a Response instance * @param string $format the format for which a formatter has been registered * @throws \DomainException if format does not match a registered formatter * @return Response diff --git a/lib/public/AppFramework/PublicShareController.php b/lib/public/AppFramework/PublicShareController.php index 706dc0b9ae9..999b3827565 100644 --- a/lib/public/AppFramework/PublicShareController.php +++ b/lib/public/AppFramework/PublicShareController.php @@ -1,27 +1,9 @@ <?php declare(strict_types=1); - /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework; @@ -36,7 +18,7 @@ use OCP\ISession; * * Use this for example for a controller that is not to be called via a webbrowser * directly. For example a PublicPreviewController. As this is not meant to be - * called by a user direclty. + * called by a user directly. * * To show an auth page extend the AuthPublicShareController * @@ -53,8 +35,8 @@ abstract class PublicShareController extends Controller { * @since 14.0.0 */ public function __construct(string $appName, - IRequest $request, - ISession $session) { + IRequest $request, + ISession $session) { parent::__construct($appName, $request); $this->session = $session; @@ -86,7 +68,7 @@ abstract class PublicShareController extends Controller { * * @since 14.0.0 */ - abstract protected function getPasswordHash(): string; + abstract protected function getPasswordHash(): ?string; /** * Is the provided token a valid token @@ -116,8 +98,8 @@ abstract class PublicShareController extends Controller { } // If we are authenticated properly - if ($this->session->get('public_link_authenticated_token') === $this->getToken() && - $this->session->get('public_link_authenticated_password_hash') === $this->getPasswordHash()) { + if ($this->session->get('public_link_authenticated_token') === $this->getToken() + && $this->session->get('public_link_authenticated_password_hash') === $this->getPasswordHash()) { return true; } diff --git a/lib/public/AppFramework/QueryException.php b/lib/public/AppFramework/QueryException.php index 3b73c92e7be..20a964e82c8 100644 --- a/lib/public/AppFramework/QueryException.php +++ b/lib/public/AppFramework/QueryException.php @@ -1,28 +1,10 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework; @@ -32,7 +14,7 @@ use Psr\Container\ContainerExceptionInterface; /** * Class QueryException * - * The class extends `NotFoundExceptionInterface` since 20.0.0 + * The class extends `ContainerExceptionInterface` since 20.0.0 * * @since 8.1.0 * @deprecated 20.0.0 catch \Psr\Container\ContainerExceptionInterface diff --git a/lib/public/AppFramework/Services/IAppConfig.php b/lib/public/AppFramework/Services/IAppConfig.php index baac2946e3c..aa95e665604 100644 --- a/lib/public/AppFramework/Services/IAppConfig.php +++ b/lib/public/AppFramework/Services/IAppConfig.php @@ -3,28 +3,13 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Services; +use OCP\Exceptions\AppConfigUnknownKeyException; + /** * Wrapper for AppConfig for the AppFramework * @@ -37,7 +22,58 @@ interface IAppConfig { * @return string[] the keys stored for the app * @since 20.0.0 */ - public function getAppKeys(): array ; + public function getAppKeys(): array; + + /** + * Check if a key exists in the list of stored config values. + * + * @param string $key config key + * @param bool $lazy search within lazy loaded config + * + * @return bool TRUE if key exists + * @since 29.0.0 + */ + public function hasAppKey(string $key, ?bool $lazy = false): bool; + + /** + * best way to see if a value is set as sensitive (not displayed in report) + * + * @param string $key config key + * @param bool|null $lazy search within lazy loaded config + * + * @return bool TRUE if value is sensitive + * @throws AppConfigUnknownKeyException if config key is not known + * @since 29.0.0 + */ + public function isSensitive(string $key, ?bool $lazy = false): bool; + + /** + * Returns if the config key stored in database is lazy loaded + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $key config key + * + * @return bool TRUE if config is lazy loaded + * @throws AppConfigUnknownKeyException if config key is not known + * @see IAppConfig for details about lazy loading + * @since 29.0.0 + */ + public function isLazy(string $key): bool; + + /** + * List all config values from an app with config key starting with $key. + * Returns an array with config key as key, stored value as value. + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $key config keys prefix to search, can be empty. + * @param bool $filtered filter sensitive config values + * + * @return array<string, string|int|float|bool|array> [configKey => configValue] + * @since 29.0.0 + */ + public function getAllAppValues(string $key = '', bool $filtered = false): array; /** * Writes a new app wide value @@ -46,20 +82,197 @@ interface IAppConfig { * @param string $value the value that should be stored * @return void * @since 20.0.0 + * @deprecated 29.0.0 use {@see setAppValueString()} */ public function setAppValue(string $key, string $value): void; /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param string $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueString(string $key, string $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database + * + * When handling huge value around and/or above 2,147,483,647, a debug log will be generated + * on 64bits system, as php int type reach its limit (and throw an exception) on 32bits when using huge numbers. + * + * When using huge numbers, it is advised to use {@see \OCP\Util::numericToNumber()} and {@see setValueString()} + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param int $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueInt(string $key, int $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database. + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param float $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueFloat(string $key, float $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param bool $value config value + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueBool(string $key, bool $value, bool $lazy = false): bool; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param array $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueArray(string $key, array $value, bool $lazy = false, bool $sensitive = false): bool; + + /** * Looks up an app wide defined value * * @param string $key the key of the value, under which it was saved * @param string $default the default value to be returned if the value isn't set + * * @return string the saved value * @since 20.0.0 + * @deprecated 29.0.0 use {@see getAppValueString()} */ public function getAppValue(string $key, string $default = ''): string; /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param string $default default value + * @param bool $lazy search within lazy loaded config + * + * @return string stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueString(string $key, string $default = '', bool $lazy = false): string; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param int $default default value + * @param bool $lazy search within lazy loaded config + * + * @return int stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueInt(string $key, int $default = 0, bool $lazy = false): int; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param float $default default value + * @param bool $lazy search within lazy loaded config + * + * @return float stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueFloat(string $key, float $default = 0, bool $lazy = false): float; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param bool $default default value + * @param bool $lazy search within lazy loaded config + * + * @return bool stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueBool(string $key, bool $default = false, bool $lazy = false): bool; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param array $default default value + * @param bool $lazy search within lazy loaded config + * + * @return array stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueArray(string $key, array $default = [], bool $lazy = false): array; + + /** * Delete an app wide defined value * * @param string $key the key of the value, under which it was saved diff --git a/lib/public/AppFramework/Services/IInitialState.php b/lib/public/AppFramework/Services/IInitialState.php index 1a597567e19..ac58bcad3cc 100644 --- a/lib/public/AppFramework/Services/IInitialState.php +++ b/lib/public/AppFramework/Services/IInitialState.php @@ -3,27 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Services; @@ -56,7 +37,7 @@ interface IInitialState { * * @param string $key * @param Closure $closure returns a primitive or an object that implements JsonSerializable - * @psalm-param Closure():bool|Closure():int|Closure():float|Closure():string|Closure():\JsonSerializable $closure + * @psalm-param Closure():bool|Closure():int|Closure():float|Closure():string|Closure():array|Closure():\JsonSerializable $closure */ public function provideLazyInitialState(string $key, Closure $closure): void; } diff --git a/lib/public/AppFramework/Services/InitialStateProvider.php b/lib/public/AppFramework/Services/InitialStateProvider.php index b9956b5fa71..d1607bc2262 100644 --- a/lib/public/AppFramework/Services/InitialStateProvider.php +++ b/lib/public/AppFramework/Services/InitialStateProvider.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Services; diff --git a/lib/public/AppFramework/Utility/IControllerMethodReflector.php b/lib/public/AppFramework/Utility/IControllerMethodReflector.php index a091c8b3707..95d7fbebb56 100644 --- a/lib/public/AppFramework/Utility/IControllerMethodReflector.php +++ b/lib/public/AppFramework/Utility/IControllerMethodReflector.php @@ -1,29 +1,10 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Utility; @@ -50,9 +31,9 @@ interface IControllerMethodReflector { * Inspects the PHPDoc parameters for types * * @param string $parameter the parameter whose type comments should be - * parsed + * parsed * @return string|null type in the type parameters (@param int $something) - * would return int or null if not existing + * would return int or null if not existing * @since 8.0.0 * @deprecated 22.0.0 this method is only used internally */ diff --git a/lib/public/AppFramework/Utility/ITimeFactory.php b/lib/public/AppFramework/Utility/ITimeFactory.php index 92101fd3848..cd63b94dee3 100644 --- a/lib/public/AppFramework/Utility/ITimeFactory.php +++ b/lib/public/AppFramework/Utility/ITimeFactory.php @@ -3,34 +3,23 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\AppFramework\Utility; +use Psr\Clock\ClockInterface; + /** - * Needed to mock calls to time() + * Use this to get a timestamp or DateTime object in code to remain testable + * * @since 8.0.0 + * @since 27.0.0 Extends the \Psr\Clock\ClockInterface interface + * @ref https://www.php-fig.org/psr/psr-20/#21-clockinterface */ -interface ITimeFactory { + +interface ITimeFactory extends ClockInterface { /** * @return int the result of a call to time() * @since 8.0.0 @@ -39,9 +28,24 @@ interface ITimeFactory { /** * @param string $time - * @param \DateTimeZone $timezone + * @param \DateTimeZone|null $timezone * @return \DateTime * @since 15.0.0 */ - public function getDateTime(string $time = 'now', \DateTimeZone $timezone = null): \DateTime; + public function getDateTime(string $time = 'now', ?\DateTimeZone $timezone = null): \DateTime; + + /** + * @param \DateTimeZone $timezone + * @return static + * @since 26.0.0 + */ + public function withTimeZone(\DateTimeZone $timezone): static; + + /** + * @param string|null $timezone + * @return \DateTimeZone Requested timezone if provided, UTC otherwise + * @throws \Exception + * @since 29.0.0 + */ + public function getTimeZone(?string $timezone = null): \DateTimeZone; } |