Issue #3225354 by eddie_c, paulocs, Bhanu951, daffie, Spokje, Berdir: Add a clearByPrefix() method to the flood API
parent
9dc5c66ea2
commit
be7d65ecf1
|
@ -9,7 +9,7 @@ use Drupal\Core\Database\Connection;
|
|||
/**
|
||||
* Defines the database flood backend. This is the default Drupal backend.
|
||||
*/
|
||||
class DatabaseBackend implements FloodInterface {
|
||||
class DatabaseBackend implements FloodInterface, PrefixFloodInterface {
|
||||
|
||||
/**
|
||||
* The database table name.
|
||||
|
@ -107,6 +107,21 @@ class DatabaseBackend implements FloodInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearByPrefix(string $name, string $prefix): void {
|
||||
try {
|
||||
$this->connection->delete(static::TABLE_NAME)
|
||||
->condition('event', $name)
|
||||
->condition('identifier', $prefix . '-%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->catchException($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,10 @@ interface FloodInterface {
|
|||
* table from growing indefinitely.
|
||||
* @param string $identifier
|
||||
* (optional) Unique identifier of the current user. Defaults to the current
|
||||
* user's IP address).
|
||||
* user's IP address. The identifier can be given an additional prefix
|
||||
* separated by "-". Flood backends may then optionally implement the
|
||||
* PrefixFloodInterface which allows all flood events that share the same
|
||||
* prefix to be cleared simultaneously.
|
||||
*/
|
||||
public function register($name, $window = 3600, $identifier = NULL);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
|
|||
/**
|
||||
* Defines the memory flood backend. This is used for testing.
|
||||
*/
|
||||
class MemoryBackend implements FloodInterface {
|
||||
class MemoryBackend implements FloodInterface, PrefixFloodInterface {
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
|
@ -54,6 +54,20 @@ class MemoryBackend implements FloodInterface {
|
|||
unset($this->events[$name][$identifier]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearByPrefix(string $name, string $prefix): void {
|
||||
foreach ($this->events as $event_name => $identifier) {
|
||||
$identifier_key = key($identifier);
|
||||
$identifier_parts = explode("-", $identifier_key);
|
||||
$identifier_prefix = reset($identifier_parts);
|
||||
if ($prefix == $identifier_prefix && $name == $event_name) {
|
||||
unset($this->events[$event_name][$identifier_key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Core\Flood;
|
||||
|
||||
/**
|
||||
* Defines an interface for flood controllers that clear by identifier prefix.
|
||||
*/
|
||||
interface PrefixFloodInterface {
|
||||
|
||||
/**
|
||||
* Makes the flood control mechanism forget an event by identifier prefix.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of an event.
|
||||
* @param string $prefix
|
||||
* The prefix of the identifier to be cleared.
|
||||
*/
|
||||
public function clearByPrefix(string $name, string $prefix): void;
|
||||
|
||||
}
|
|
@ -115,4 +115,41 @@ class FloodTest extends KernelTestBase {
|
|||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an array of backends for testClearByPrefix.
|
||||
*/
|
||||
public function floodBackendProvider() :array {
|
||||
$request_stack = \Drupal::service('request_stack');
|
||||
$connection = \Drupal::service('database');
|
||||
|
||||
return [
|
||||
new MemoryBackend($request_stack),
|
||||
new DatabaseBackend($connection, $request_stack),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests clearByPrefix method on flood backends.
|
||||
*/
|
||||
public function testClearByPrefix() {
|
||||
$threshold = 1;
|
||||
$window_expired = 3600;
|
||||
$identifier = 'prefix-127.0.0.1';
|
||||
$name = 'flood_test_cleanup';
|
||||
|
||||
// We can't use an PHPUnit data provider because we need access to the
|
||||
// container.
|
||||
$backends = $this->floodBackendProvider();
|
||||
|
||||
foreach ($backends as $backend) {
|
||||
// Register unexpired event.
|
||||
$backend->register($name, $window_expired, $identifier);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($backend->isAllowed($name, $threshold, $window_expired, $identifier));
|
||||
// Clear by prefix and verify event is now allowed.
|
||||
$backend->clearByPrefix($name, 'prefix');
|
||||
$this->assertTrue($backend->isAllowed($name, $threshold));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue