aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2023-09-06 10:04:14 +0200
committerChristoph Wurst <christoph@winzerhof-wurst.at>2023-09-20 20:25:27 +0200
commite477bb7eaf0d4bd220361ceb47ac4bcca9b438bf (patch)
tree026fbbaf989b2b522b65be8d2d815ff581864fe3 /lib
parent2bd0f07e5a1bb1a83ec3b1c86c1a1271dcdad9e3 (diff)
downloadnextcloud-server-e477bb7eaf0d4bd220361ceb47ac4bcca9b438bf.tar.gz
nextcloud-server-e477bb7eaf0d4bd220361ceb47ac4bcca9b438bf.zip
feat(appframework): Expose programmatic rate limiter
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/autoload_classmap.php2
-rw-r--r--lib/composer/composer/autoload_static.php2
-rw-r--r--lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php3
-rw-r--r--lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php3
-rw-r--r--lib/private/Security/RateLimiting/Limiter.php3
-rw-r--r--lib/private/Server.php4
-rw-r--r--lib/public/Security/RateLimiting/ILimiter.php72
-rw-r--r--lib/public/Security/RateLimiting/IRateLimitExceededException.php36
8 files changed, 123 insertions, 2 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index fb063a82088..a83ad16b8f1 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -583,6 +583,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 35b2318c4b1..ecc158213bc 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -616,6 +616,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 ba8b18f9a05..b349f4ec278 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -142,6 +142,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;
@@ -239,6 +240,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;
@@ -1414,6 +1416,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 {
+}