-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WIP] - Initial commit from internal component (#1)
- Loading branch information
Showing
33 changed files
with
1,717 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 4 | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[Makefile] | ||
indent_style = tab | ||
|
||
[*.md] | ||
trim_trailing_whitespace = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/vendor/ | ||
/bin/ | ||
composer.lock | ||
.phpunit.result.cache | ||
.php_cs.cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
$config = new M6Web\CS\Config\Php74(); | ||
|
||
$config->getFinder() | ||
->in([ | ||
__DIR__.'/src', | ||
__DIR__.'/tests' | ||
]); | ||
|
||
return $config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
SHELL=bash -o pipefail | ||
SOURCE_DIR = $(shell pwd) | ||
BIN_DIR = ${SOURCE_DIR}/bin | ||
COMPOSER = composer | ||
|
||
define printSection | ||
@printf "\033[36m\n==================================================\n\033[0m" | ||
@printf "\033[36m $1 \033[0m" | ||
@printf "\033[36m\n==================================================\n\033[0m" | ||
endef | ||
|
||
.PHONY: all | ||
all: install quality test | ||
|
||
.PHONY: ci | ||
ci: quality test | ||
|
||
.PHONY: install | ||
install: clean-vendor composer-install | ||
|
||
.PHONY: quality | ||
quality: cs-ci phpstan | ||
|
||
.PHONY: test | ||
test: phpunit | ||
|
||
### DEPENDENCIES ### | ||
|
||
.PHONY: clean-vendor | ||
clean-vendor: | ||
$(call printSection,DEPENDENCIES clean) | ||
rm -rf ${SOURCE_DIR}/vendor | ||
|
||
.PHONY: composer-install | ||
composer-install: ${SOURCE_DIR}/vendor/composer/installed.json | ||
|
||
${SOURCE_DIR}/vendor/composer/installed.json: | ||
$(call printSection,DEPENDENCIES install) | ||
$(COMPOSER) --no-interaction install --ansi --no-progress --prefer-dist | ||
|
||
### TEST ### | ||
|
||
.PHONY: phpunit | ||
phpunit: | ||
$(call printSection,TEST phpunit) | ||
${BIN_DIR}/phpunit | ||
|
||
### QUALITY ### | ||
|
||
.PHONY: phpstan | ||
phpstan: | ||
$(call printSection,QUALITY phpstan) | ||
${BIN_DIR}/phpstan analyse --memory-limit=1G | ||
|
||
.PHONY: cs-ci | ||
cs-ci: | ||
$(call printSection,QUALITY php-cs-fixer check) | ||
${BIN_DIR}/php-cs-fixer fix --ansi --dry-run --using-cache=no --verbose | ||
|
||
.PHONY: cs-fix | ||
cs-fix: | ||
$(call printSection,QUALITY php-cs-fixer fix) | ||
${BIN_DIR}/php-cs-fixer fix | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# RateLimitBundle | ||
This bundle provides an easy way to protect your project by limiting access to your controllers. | ||
|
||
## Install the bundle | ||
```bash | ||
composer require bedrock/rate-limit-bundle | ||
``` | ||
|
||
Update your _config/bundles.php_ file to add the bundle for all env | ||
```php | ||
<?php | ||
|
||
return [ | ||
... | ||
Bedrock\Bundle\RateLimitBundle\RateLimitBundle::class => ['all' => true], | ||
... | ||
]; | ||
``` | ||
|
||
### Configure the bundle | ||
Add the _config/packages/bedrock_rate_limit.yaml_ file with the following data. | ||
```yaml | ||
bedrock_rate_limit: | ||
limit: 25 # 1000 requests by default | ||
period: 600 # 60 seconds by default | ||
limit_by_route: true|false # false by default | ||
display_headers: true|false # false by default | ||
``` | ||
By default, the limitation is common to all routes annotated `@RateLimit()`. | ||
For example, if you keep the default configuration and you configure the `@RateLimit()` annotation in 2 routes. Limit will shared between this 2 routes, if user consume all authorized calls on the first route, the second route couldn't be called. | ||
If you swicth `limit_by_route` to true, users will be allowed to reach the limit on each route annotated. | ||
|
||
If you switch `display_headers` to true, 3 headers will be added `x-rate-limit`, `x-rate-limit-hits`, `x-rate-limit-untils` to your responses. This can be usefull to debug your limitations. | ||
`display_headers` is used to display a verbose return if limit is reached. | ||
|
||
### Configure your storage | ||
You must tell Symfony which storage implementation you want to use. | ||
|
||
Update your _config/services.yml_ like this: | ||
|
||
```yaml | ||
... | ||
Bedrock\Bundle\RateLimitBundle\Storage\RateLimitStorageInterface: '@Bedrock\Bundle\RateLimitBundle\Storage\RateLimitInMemoryStorage' | ||
... | ||
``` | ||
|
||
By default, only `RateLimitInMemory` is provided. But feel free to create your own by implementing `RateLimitStorageInterface` or `ManuallyResetableRateLimitStorageInterface`. | ||
If your database has a TTL system (like Redis), you can implement only `RateLimitStorageInterface`. Otherwhise you must implement also `ManuallyResetableRateLimitStorageInterface` to manually delete rate limit in your database. | ||
|
||
### Configure your modifiers | ||
Modifiers are a way to customize the rate limit. | ||
|
||
This bundle provides 2 modifiers: | ||
* `HttpMethodRateLimitModifier` limits the requests by `http_method`. | ||
* `RequestAttributeRateLimitModifier` limits the requests by attributes value (taken from the `$request->attributes` Symfony's bag). | ||
|
||
Update your _config/services.yml_ like this: | ||
|
||
```yaml | ||
... | ||
Bedrock\Bundle\RateLimitBundle\RateLimitModifier\HttpMethodRateLimitModifier: | ||
tags: [ 'rate_limit.modifiers' ] | ||
Bedrock\Bundle\RateLimitBundle\RateLimitModifier\RequestAttributeRateLimitModifier: | ||
arguments: | ||
$attributeName: 'myRequestAttribute' | ||
tags: [ 'rate_limit.modifiers' ] | ||
... | ||
``` | ||
|
||
You can also create your own rate limit modifier by implementing `RateLimitModifierInterface` and tagging your service accordingly. | ||
|
||
### Configure your routes | ||
Add the `@RateLimit()` annotation to your controller methods (by default, the limit will be 1000 requests per minute). | ||
This annotation accepts parameters to customize the rate limit. The following example shows how to limit requests on a route at the rate of 10 requests max every 2 minutes. | ||
:warning: This customization only works if the `limit_by_route` parameter is `true` | ||
|
||
```php | ||
/** | ||
* @RateLimit( | ||
* limit=10, | ||
* period=120 | ||
* ) | ||
*/ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"name": "bedrock/rate-limit-bundle", | ||
"type": "symfony-bundle", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Bedrock", | ||
"email": "[email protected]", | ||
"homepage": "https://tech.bedrockstreaming.com/" | ||
} | ||
], | ||
"config": { | ||
"bin-dir": "bin", | ||
"vendor-dir": "vendor", | ||
"sort-packages": true | ||
}, | ||
"require": { | ||
"php": "7.4.*", | ||
"ext-json": "*", | ||
"doctrine/annotations": "^1.10.0", | ||
"symfony/dependency-injection": "4.4.*", | ||
"symfony/event-dispatcher": "4.4.*", | ||
"symfony/http-foundation": "4.4.*", | ||
"symfony/http-kernel": "4.4.*", | ||
"symfony/config": "4.4.*" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "9.4.*", | ||
"m6web/php-cs-fixer-config": "1.3.*", | ||
"phpstan/phpstan": "0.12.*", | ||
"phpstan/phpstan-phpunit": "0.12.*", | ||
"symfony/var-dumper": "4.4.*" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"Bedrock\\Bundle\\RateLimitBundle\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"Bedrock\\Bundle\\RateLimitBundle\\Tests\\": "tests/" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
includes: | ||
- 'vendor/phpstan/phpstan-phpunit/extension.neon' | ||
- 'vendor/phpstan/phpstan-phpunit/rules.neon' | ||
|
||
parameters: | ||
paths: | ||
- 'src' | ||
- 'tests' | ||
level: 'max' | ||
checkGenericClassInNonGenericObjectType: false | ||
ignoreErrors: | ||
- '#Cannot call method integerNode\(\) on Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface\|null\.#' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html --> | ||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php"> | ||
<coverage> | ||
<include> | ||
<directory>src</directory> | ||
</include> | ||
</coverage> | ||
<php> | ||
<ini name="error_reporting" value="-1"/> | ||
<server name="SHELL_VERBOSITY" value="-1"/> | ||
<env name="APP_ENV" value="test" /> | ||
</php> | ||
<testsuites> | ||
<testsuite name="Project Test Suite"> | ||
<directory>tests</directory> | ||
</testsuite> | ||
</testsuites> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Bedrock\Bundle\RateLimitBundle\Annotation; | ||
|
||
/** | ||
* @Annotation | ||
* @Target({"METHOD"}) | ||
*/ | ||
final class RateLimit | ||
{ | ||
private ?int $limit; | ||
private ?int $period; | ||
|
||
/** | ||
* @param array<string, int> $args | ||
*/ | ||
public function __construct(array $args = []) | ||
{ | ||
$this->limit = $args['limit'] ?? null; | ||
$this->period = $args['period'] ?? null; | ||
} | ||
|
||
public function getLimit(): ?int | ||
{ | ||
return $this->limit; | ||
} | ||
|
||
public function setLimit(int $limit): RateLimit | ||
{ | ||
$this->limit = $limit; | ||
|
||
return $this; | ||
} | ||
|
||
public function getPeriod(): ?int | ||
{ | ||
return $this->period; | ||
} | ||
|
||
public function setPeriod(int $period): RateLimit | ||
{ | ||
$this->period = $period; | ||
|
||
return $this; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Bedrock\Bundle\RateLimitBundle\DependencyInjection; | ||
|
||
use Symfony\Component\Config\FileLocator; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | ||
use Symfony\Component\HttpKernel\DependencyInjection\Extension; | ||
|
||
class BedrockRateLimitExtension extends Extension | ||
{ | ||
/** | ||
* Override conf key for this bundle | ||
*/ | ||
public function getAlias(): string | ||
{ | ||
return 'bedrock_rate_limit'; | ||
} | ||
|
||
/** | ||
* @param array<mixed> $configs | ||
*/ | ||
public function load(array $configs, ContainerBuilder $container): void | ||
{ | ||
$configuration = new Configuration(); | ||
$config = $this->processConfiguration($configuration, $configs); | ||
|
||
$container->setParameter('bedrock_rate_limit.limit', $config['limit']); | ||
$container->setParameter('bedrock_rate_limit.period', $config['period']); | ||
$container->setParameter('bedrock_rate_limit.limit_by_route', $config['limit_by_route']); | ||
$container->setParameter('bedrock_rate_limit.display_headers', $config['display_headers']); | ||
|
||
$loader = new YamlFileLoader( | ||
$container, | ||
new FileLocator(__DIR__.'/../Resources/config') | ||
); | ||
$loader->load('services.yml'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Bedrock\Bundle\RateLimitBundle\DependencyInjection; | ||
|
||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; | ||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; | ||
use Symfony\Component\Config\Definition\ConfigurationInterface; | ||
|
||
class Configuration implements ConfigurationInterface | ||
{ | ||
public function getConfigTreeBuilder(): TreeBuilder | ||
{ | ||
$treeBuilder = new TreeBuilder('bedrock_rate_limit'); | ||
/** @var ArrayNodeDefinition $rootNode */ | ||
$rootNode = $treeBuilder->getRootNode(); | ||
|
||
$rootNode | ||
->children() | ||
->booleanNode('limit_by_route') | ||
->defaultValue(false) | ||
->end() | ||
->integerNode('limit') | ||
->defaultValue(1000) | ||
->min(0) | ||
->end() | ||
->integerNode('period') | ||
->defaultValue(60) | ||
->min(0) | ||
->end() | ||
->booleanNode('display_headers') | ||
->defaultValue(false) | ||
->end() | ||
->end() | ||
; | ||
|
||
return $treeBuilder; | ||
} | ||
} |
Oops, something went wrong.