Flood isAllowed ignores windows

Created on 5 October 2020, over 4 years ago
Updated 24 June 2024, 10 months ago

Problem/Motivation

Whilst not the core or general way to make use of flood register/isAllowed, it is possible/em> to use different windows for ::register and ::isAllowed. The current implementation ignores $window in ::isAllowed

Proposed resolution

Store the current time rather than the expiration time in ::register. ::isAllowed can then use the current time minus the window for the start param to $this->client->zCount(...).

🐛 Bug report
Status

Active

Version

1.0

Component

Code

Created by

🇬🇧United Kingdom andrewbelcher

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇨🇿Czech Republic siva01

    I can confirm this issue. I have version Drupal Redis 1.7.0.

    Drupal\redis\Flood\PhpRedis

     /**
       * {@inheritdoc}
       */
      public function isAllowed($name, $threshold, $window = 3600, $identifier = NULL) {
        if (!isset($identifier)) {
          $identifier = $this->requestStack->getCurrentRequest()->getClientIp();
        }
    
        $key = $this->getPrefix() . ':flood:' . $name . ':' . $identifier;
    
        // Count the in the last $window seconds.
        $number = $this->client->zCount($key, $_SERVER['REQUEST_TIME'], 'inf');
        return ($number < $threshold);
      }

    $window isn't used in that function.

    I think, that it should look as:

     /**
       * {@inheritdoc}
       */
      public function isAllowed($name, $threshold, $window = 3600, $identifier = NULL) {
        if (!isset($identifier)) {
          $identifier = $this->requestStack->getCurrentRequest()->getClientIp();
        }
    
        $key = $this->getPrefix() . ':flood:' . $name . ':' . $identifier;
    
        // Count the in the last $window seconds.
        $number = $this->client->zCount($key, $_SERVER['REQUEST_TIME'] - $window, 'inf');
        return ($number < $threshold);
      }
  • First commit to issue fork.
  • 🇵🇱Poland krystianbuczak

    Hi @siva01,

    even with passed $window argument the code seemed to not work properly. I tried to limit 10 requests within 1 minute window and Redis didn't expire my event properly. I have just added my proposal of the issue:

    In register() method

    BEFORE:

    $this->client->zAdd($key, $_SERVER['REQUEST_TIME'] + $window, microtime(TRUE));
    $this->client->expire($key, $_SERVER['REQUEST_TIME'] + $window);
    

    AFTER

    $this->client->zAdd($key, microtime(TRUE), microtime(TRUE));
    $this->client->expire($key, $window);
    

    In isAllowed() method

    BEFORE

    $number = $this->client->zCount($key, $_SERVER['REQUEST_TIME'], 'inf');
    return ($number < $threshold);
    

    AFTER

    $number = $this->client->zCount($key, microtime(TRUE) - $window, 'inf');
    return $number < $threshold;
    

    + redundant comments removal.

    microtime() is used for consistency.

Production build 0.71.5 2024