diff options
author | Joas Schilling <213943+nickvergessen@users.noreply.github.com> | 2023-09-21 18:49:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-21 18:49:44 +0200 |
commit | 3b6a9cd23628464cd24da3d426764a8232124f33 (patch) | |
tree | 4a4c814ef8b500d84748dba95e2d5b05ba2d26c6 /lib | |
parent | b11ca34bbd0c2d5fdbb6b68b3e1bf93dad02f588 (diff) | |
parent | e477bb7eaf0d4bd220361ceb47ac4bcca9b438bf (diff) | |
download | nextcloud-server-3b6a9cd23628464cd24da3d426764a8232124f33.tar.gz nextcloud-server-3b6a9cd23628464cd24da3d426764a8232124f33.zip |
Merge pull request #40288 from nextcloud/feat/appframework/rate-limiter
feat(appframework): Expose programmatic rate limiter
Diffstat (limited to 'lib')
8 files changed, 123 insertions, 2 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 34e7ddc2201..8c4d8229422 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -588,6 +588,8 @@ return array( 'OCP\\Security\\IRemoteHostValidator' => $baseDir . '/lib/public/Security/IRemoteHostValidator.php', 'OCP\\Security\\ISecureRandom' => $baseDir . '/lib/public/Security/ISecureRandom.php', 'OCP\\Security\\ITrustedDomainHelper' => $baseDir . '/lib/public/Security/ITrustedDomainHelper.php', + 'OCP\\Security\\RateLimiting\\ILimiter' => $baseDir . '/lib/public/Security/RateLimiting/ILimiter.php', + 'OCP\\Security\\RateLimiting\\IRateLimitExceededException' => $baseDir . '/lib/public/Security/RateLimiting/IRateLimitExceededException.php', 'OCP\\Security\\VerificationToken\\IVerificationToken' => $baseDir . '/lib/public/Security/VerificationToken/IVerificationToken.php', 'OCP\\Security\\VerificationToken\\InvalidTokenException' => $baseDir . '/lib/public/Security/VerificationToken/InvalidTokenException.php', 'OCP\\Server' => $baseDir . '/lib/public/Server.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index be381751d7b..6ed91a7d67f 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -621,6 +621,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Security\\IRemoteHostValidator' => __DIR__ . '/../../..' . '/lib/public/Security/IRemoteHostValidator.php', 'OCP\\Security\\ISecureRandom' => __DIR__ . '/../../..' . '/lib/public/Security/ISecureRandom.php', 'OCP\\Security\\ITrustedDomainHelper' => __DIR__ . '/../../..' . '/lib/public/Security/ITrustedDomainHelper.php', + 'OCP\\Security\\RateLimiting\\ILimiter' => __DIR__ . '/../../..' . '/lib/public/Security/RateLimiting/ILimiter.php', + 'OCP\\Security\\RateLimiting\\IRateLimitExceededException' => __DIR__ . '/../../..' . '/lib/public/Security/RateLimiting/IRateLimitExceededException.php', 'OCP\\Security\\VerificationToken\\IVerificationToken' => __DIR__ . '/../../..' . '/lib/public/Security/VerificationToken/IVerificationToken.php', 'OCP\\Security\\VerificationToken\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/public/Security/VerificationToken/InvalidTokenException.php', 'OCP\\Server' => __DIR__ . '/../../..' . '/lib/public/Server.php', diff --git a/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php b/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php index 3232980b7e5..3b2296c145f 100644 --- a/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php +++ b/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * diff --git a/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php b/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php index 08091e997ca..baf74927886 100644 --- a/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php +++ b/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php @@ -27,8 +27,9 @@ namespace OC\Security\RateLimiting\Exception; use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; use OCP\AppFramework\Http; +use OCP\Security\RateLimiting\IRateLimitExceededException; -class RateLimitExceededException extends SecurityException { +class RateLimitExceededException extends SecurityException implements IRateLimitExceededException { public function __construct() { parent::__construct('Rate limit exceeded', Http::STATUS_TOO_MANY_REQUESTS); } diff --git a/lib/private/Security/RateLimiting/Limiter.php b/lib/private/Security/RateLimiting/Limiter.php index c8c0e2ce101..689e7b14558 100644 --- a/lib/private/Security/RateLimiting/Limiter.php +++ b/lib/private/Security/RateLimiting/Limiter.php @@ -30,8 +30,9 @@ use OC\Security\Normalizer\IpAddress; use OC\Security\RateLimiting\Backend\IBackend; use OC\Security\RateLimiting\Exception\RateLimitExceededException; use OCP\IUser; +use OCP\Security\RateLimiting\ILimiter; -class Limiter { +class Limiter implements ILimiter { public function __construct( private IBackend $backend, ) { diff --git a/lib/private/Server.php b/lib/private/Server.php index c874591f576..7ab57478f44 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -143,6 +143,7 @@ use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OC\Security\CSRF\CsrfTokenManager; use OC\Security\CSRF\TokenStorage\SessionStorage; use OC\Security\Hasher; +use OC\Security\RateLimiting\Limiter; use OC\Security\SecureRandom; use OC\Security\TrustedDomainHelper; use OC\Security\VerificationToken\VerificationToken; @@ -241,6 +242,7 @@ use OCP\Security\ICrypto; use OCP\Security\IHasher; use OCP\Security\ISecureRandom; use OCP\Security\ITrustedDomainHelper; +use OCP\Security\RateLimiting\ILimiter; use OCP\Security\VerificationToken\IVerificationToken; use OCP\Share\IShareHelper; use OCP\SpeechToText\ISpeechToTextManager; @@ -1419,6 +1421,8 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(\OCP\TextProcessing\IManager::class, \OC\TextProcessing\Manager::class); + $this->registerAlias(ILimiter::class, Limiter::class); + $this->connectDispatcher(); } diff --git a/lib/public/Security/RateLimiting/ILimiter.php b/lib/public/Security/RateLimiting/ILimiter.php new file mode 100644 index 00000000000..275746b0b49 --- /dev/null +++ b/lib/public/Security/RateLimiting/ILimiter.php @@ -0,0 +1,72 @@ +<?php + +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/>. + */ + +namespace OCP\Security\RateLimiting; + +use OCP\AppFramework\Http\Attribute\AnonRateLimit; +use OCP\AppFramework\Http\Attribute\UserRateLimit; +use OCP\IUser; + +/** + * Programmatic rate limiter for web requests that are not handled by an app framework controller + * + * @see AnonRateLimit + * @see UserRateLimit + * + * @since 28.0.0 + */ +interface ILimiter { + /** + * Registers attempt for an anonymous request + * + * @param string $identifier + * @param int $anonLimit + * @param int $anonPeriod in seconds + * @param string $ip + * @throws IRateLimitExceededException if limits are reached, which should cause a HTTP 429 response + * @since 28.0.0 + * + */ + public function registerAnonRequest(string $identifier, + int $anonLimit, + int $anonPeriod, + string $ip): void; + + /** + * Registers attempt for an authenticated request + * + * @param string $identifier + * @param int $userLimit + * @param int $userPeriod in seconds + * @param IUser $user the acting user + * @throws IRateLimitExceededException if limits are reached, which should cause a HTTP 429 response + * @since 28.0.0 + * + */ + public function registerUserRequest(string $identifier, + int $userLimit, + int $userPeriod, + IUser $user): void; +} diff --git a/lib/public/Security/RateLimiting/IRateLimitExceededException.php b/lib/public/Security/RateLimiting/IRateLimitExceededException.php new file mode 100644 index 00000000000..9bc8c22a67c --- /dev/null +++ b/lib/public/Security/RateLimiting/IRateLimitExceededException.php @@ -0,0 +1,36 @@ +<?php + +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/>. + */ + +namespace OCP\Security\RateLimiting; + +use Throwable; + +/** + * Thrown if the (anonymous) user has exceeded a rate limit + * + * @since 28.0.0 + */ +interface IRateLimitExceededException extends Throwable { +} |