From 8376c4891f84d24469bd14b1462baf637862e922 Mon Sep 17 00:00:00 2001
From: Joas Schilling <coding@schilljs.com>
Date: Thu, 19 Mar 2020 13:42:31 +0100
Subject: [PATCH] Only throw when also the last 30 mins were attacking

Signed-off-by: Joas Schilling <coding@schilljs.com>
---
 lib/private/Security/Bruteforce/Throttler.php | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php
index f2bdd9986b6..059f15e89fd 100644
--- a/lib/private/Security/Bruteforce/Throttler.php
+++ b/lib/private/Security/Bruteforce/Throttler.php
@@ -96,12 +96,12 @@ class Throttler {
 	/**
 	 *  Calculate the cut off timestamp
 	 *
-	 * @param int $maxAgeHours
+	 * @param float $maxAgeHours
 	 * @return int
 	 */
-	private function getCutoffTimestamp(int $maxAgeHours): int {
+	private function getCutoffTimestamp(float $maxAgeHours): int {
 		return (new \DateTime())
-			->sub($this->getCutoff($maxAgeHours * 3600))
+			->sub($this->getCutoff((int) ($maxAgeHours * 3600)))
 			->getTimestamp();
 	}
 
@@ -220,10 +220,10 @@ class Throttler {
 	 *
 	 * @param string $ip
 	 * @param string $action optionally filter by action
-	 * @param int $maxAgeHours
+	 * @param float $maxAgeHours
 	 * @return int
 	 */
-	public function getAttempts(string $ip, string $action = '', int $maxAgeHours = 12): int {
+	public function getAttempts(string $ip, string $action = '', float $maxAgeHours = 12): int {
 		$ipAddress = new IpAddress($ip);
 		if ($this->isIPWhitelisted((string)$ipAddress)) {
 			return 0;
@@ -329,8 +329,8 @@ class Throttler {
 	}
 
 	/**
-	 * Will sleep for the defined amount of time unless maximum is reached
-	 * In case of maximum a "429 Too Many Request" response is thrown
+	 * Will sleep for the defined amount of time unless maximum was reached in the last 30 minutes
+	 * In this case a "429 Too Many Request" exception is thrown
 	 *
 	 * @param string $ip
 	 * @param string $action optionally filter by action
@@ -339,7 +339,8 @@ class Throttler {
 	 */
 	public function sleepDelayOrThrowOnMax(string $ip, string $action = ''): int {
 		$delay = $this->getDelay($ip, $action);
-		if ($delay === self::MAX_DELAY * 1000) {
+		if (($delay === self::MAX_DELAY * 1000) && $this->getAttempts($ip, $action, 0.5) > self::MAX_ATTEMPTS) {
+			// If the ip made too many attempts within the last 30 mins we don't execute anymore
 			throw new MaxDelayReached('Reached maximum delay');
 		}
 		usleep($delay * 1000);
-- 
GitLab