Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 47 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
| TestRateLimitCommand | |
0.00% |
0 / 47 |
|
0.00% |
0 / 4 |
42 | |
0.00% |
0 / 1 |
| buildOptionParser | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
| execute | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
12 | |||
| getBaseUrl | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| generateRandomIp | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | declare(strict_types=1); |
| 3 | |
| 4 | namespace App\Command; |
| 5 | |
| 6 | use Cake\Command\Command; |
| 7 | use Cake\Console\Arguments; |
| 8 | use Cake\Console\ConsoleIo; |
| 9 | use Cake\Console\ConsoleOptionParser; |
| 10 | |
| 11 | /** |
| 12 | * TestRateLimitCommand class |
| 13 | * |
| 14 | * This command is used to test rate limiting by making multiple requests to a specified URL. |
| 15 | */ |
| 16 | class TestRateLimitCommand extends Command |
| 17 | { |
| 18 | /** |
| 19 | * Build the option parser for the command. |
| 20 | * |
| 21 | * @param \Cake\Console\ConsoleOptionParser $parser The option parser to be defined. |
| 22 | * @return \Cake\Console\ConsoleOptionParser The option parser instance. |
| 23 | */ |
| 24 | protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser |
| 25 | { |
| 26 | $parser |
| 27 | ->addOption('url', [ |
| 28 | 'short' => 'u', |
| 29 | 'help' => 'URL to test (default: /en/users/login)', |
| 30 | 'default' => '/en/users/login', |
| 31 | ]) |
| 32 | ->addOption('attempts', [ |
| 33 | 'short' => 'a', |
| 34 | 'help' => 'Number of attempts (default: 10)', |
| 35 | 'default' => '10', |
| 36 | ]); |
| 37 | |
| 38 | return $parser; |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Execute the command. |
| 43 | * |
| 44 | * @param \Cake\Console\Arguments $args The command arguments. |
| 45 | * @param \Cake\Console\ConsoleIo $io The console io. |
| 46 | * @return int|null The exit code or null for success. |
| 47 | */ |
| 48 | public function execute(Arguments $args, ConsoleIo $io): ?int |
| 49 | { |
| 50 | $url = $args->getOption('url'); |
| 51 | $attempts = (int)$args->getOption('attempts'); |
| 52 | |
| 53 | $baseUrl = $this->getBaseUrl(); |
| 54 | $fullUrl = $baseUrl . $url; |
| 55 | |
| 56 | $io->out(sprintf('Testing rate limit on URL: %s', $fullUrl)); |
| 57 | $io->out(sprintf('Number of attempts: %d', $attempts)); |
| 58 | $io->hr(); |
| 59 | |
| 60 | for ($i = 0; $i < $attempts; $i++) { |
| 61 | $ch = curl_init($fullUrl); |
| 62 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
| 63 | curl_setopt($ch, CURLOPT_TIMEOUT, 10); |
| 64 | curl_setopt($ch, CURLOPT_FAILONERROR, true); |
| 65 | |
| 66 | // Set headers to simulate a browser request |
| 67 | curl_setopt($ch, CURLOPT_HTTPHEADER, [ |
| 68 | 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' . |
| 69 | '(KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', |
| 70 | 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', |
| 71 | 'Accept-Language: en-US,en;q=0.5', |
| 72 | 'Connection: keep-alive', |
| 73 | 'Upgrade-Insecure-Requests: 1', |
| 74 | 'X-Forwarded-For: ' . $this->generateRandomIp(), |
| 75 | ]); |
| 76 | |
| 77 | $response = curl_exec($ch); |
| 78 | |
| 79 | if ($response === false) { |
| 80 | $error = curl_error($ch); |
| 81 | $errno = curl_errno($ch); |
| 82 | $io->error(sprintf('Attempt %d failed. Error (%d): %s', $i + 1, $errno, $error)); |
| 83 | } else { |
| 84 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
| 85 | $io->out(sprintf('Attempt %d: HTTP Code: %d', $i + 1, $httpCode)); |
| 86 | $io->out(sprintf('Response: %s', substr($response, 0, 100) . '...')); |
| 87 | } |
| 88 | |
| 89 | curl_close($ch); |
| 90 | $io->hr(); |
| 91 | |
| 92 | usleep(100000); // 0.1 second delay |
| 93 | } |
| 94 | |
| 95 | return static::CODE_SUCCESS; |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Get the base URL for the requests. |
| 100 | * |
| 101 | * @return string The base URL. |
| 102 | */ |
| 103 | private function getBaseUrl(): string |
| 104 | { |
| 105 | return 'http://willowcms:80'; |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * Generate a random IP address. |
| 110 | * |
| 111 | * @return string A randomly generated IP address. |
| 112 | */ |
| 113 | private function generateRandomIp(): string |
| 114 | { |
| 115 | return mt_rand(1, 255) . '.' . mt_rand(0, 255) . '.' . mt_rand(0, 255) . '.' . mt_rand(0, 255); |
| 116 | } |
| 117 | } |