Skip to content

Commit 102e1ac

Browse files
authored
Merge pull request #66 from tito10047/rate-limiter
add support for Rate limiter
2 parents c8061e5 + 09baf7e commit 102e1ac

59 files changed

Lines changed: 1532 additions & 73 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616

1717
###> symfony/framework-bundle ###
1818
APP_ENV=dev
19-
APP_SECRET=
19+
APP_SECRET=dsads45dsad4as5d4a63
2020
###< symfony/framework-bundle ###

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ concurrency:
99
group: ${{ github.workflow }}-${{ github.ref }}
1010
cancel-in-progress: true
1111

12+
env:
13+
APP_SECRET: s3cret
14+
1215
jobs:
1316
php-cs-fixer:
1417
name: "Coding Standard"
@@ -129,8 +132,27 @@ jobs:
129132
- name: "Execute tests"
130133
run: "composer test"
131134

135+
dependency-free:
136+
name: "Dependency Free (no Rate Limiter)"
137+
runs-on: ubuntu-latest
138+
steps:
139+
- name: Checkout
140+
uses: actions/checkout@v4
141+
- name: "Install PHP"
142+
uses: "shivammathur/setup-php@v2"
143+
with:
144+
php-version: "8.2"
145+
- name: "Install dependencies"
146+
run: composer update --no-interaction --no-progress
147+
- name: "Remove symfony/rate-limiter"
148+
run: composer remove symfony/rate-limiter --dev --no-interaction
149+
- name: "Run unit tests (no rate-limiter)"
150+
run: vendor/bin/phpunit tests/Unit/
151+
132152
e2e-tests:
133153
name: "E2E Test"
154+
# Recipe from version 2.0 does not work. Once we release version 3.0, we will create a recipe and restore this test.
155+
if: false
134156
runs-on: ubuntu-latest
135157

136158
steps:

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ tools/
1414
/tests/App/Twig/config/reference.php
1515
/tests/App/Webpack/config/reference.php
1616
var/cache
17-
/driver
17+
/driver/

MIGRATE.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,27 @@ module.exports.resolve.alias["altcha/dist/i18n/all.js"] = 'altcha/i18n';
2222

2323
## Configuration
2424

25-
The configuration remains mostly backward compatible, but it is recommended to update to the new keys.
26-
2725
| Old Key | New Key | Status |
2826
|---------|---------|--------|
29-
| `hmacKey` | `hmacSignature` | Deprecated (fallback exists) |
27+
| `hmacKey` | `hmacSignature` | **BC break: removed, use `hmacSignature`** |
3028
| `max_number` | - | Deprecated (replaced by `cost` and `counter_max`) |
3129

30+
### BC Break: `hmacKey` removed
31+
32+
The `hmacKey` configuration option has been **removed**. There is no automatic migration.
33+
34+
Update your config manually:
35+
36+
```yaml
37+
# Before (2.x)
38+
altcha:
39+
hmacKey: '%env(APP_SECRET)%'
40+
41+
# After (3.0)
42+
altcha:
43+
hmacSignature: '%env(APP_SECRET)%'
44+
```
45+
3246
### New Configuration Options
3347
- `hmacAlgorithm`: Specify the HMAC algorithm (default: `SHA-256`).
3448
- `hmacKeySignature`: Optional signature key.

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,39 @@ altcha:
176176
Activating this configuration will have the effect to use the sentinel server to generate a new challenge and for it's verification.
177177
If the sentinel instance is not reachable by the client or by the server, we will fallback on our local configuration.
178178

179+
### Optional: Rate Limiting
180+
181+
Rate limiting prevents the same challenge token from being validated multiple times (replay attack protection). Requires `symfony/rate-limiter`:
182+
183+
```bash
184+
composer require symfony/rate-limiter
185+
```
186+
187+
Configure a rate limiter policy:
188+
189+
```yaml
190+
# config/packages/framework.yaml
191+
framework:
192+
rate_limiter:
193+
altcha_challenge:
194+
policy: 'fixed_window'
195+
limit: 1
196+
interval: '15 minutes'
197+
```
198+
199+
Reference the limiter service in the altcha config:
200+
201+
```yaml
202+
# config/packages/altcha.yaml
203+
altcha:
204+
hmacSignature: '%env(APP_SECRET)%'
205+
rate_limiter: 'limiter.altcha_challenge'
206+
```
207+
208+
The challenge signature is used as the rate limiter key. With the configuration above, each unique challenge token can only be validated **once** per 15 minutes. If the limit is exceeded, the form will display: *"Too many attempts. Please try again later."*
209+
210+
If `symfony/rate-limiter` is not installed and `rate_limiter` is configured, the container build will throw a `LogicException` with a helpful message.
211+
179212
## License
180213

181214
The MIT License (MIT). Please see [License File](LICENSE) for more information.

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@
4949

5050
}
5151
},
52+
"suggest": {
53+
"symfony/rate-limiter": "Allows rate limiting of captcha validation attempts per challenge token"
54+
},
5255
"require-dev": {
5356
"phpstan/phpstan": "^1.8",
5457
"phpstan/phpstan-symfony": "^1.2",
5558
"rector/rector": "^0.14.5",
5659
"phpunit/phpunit": "^10.5",
5760
"ext-ctype": "*",
5861
"ext-iconv": "*",
62+
"symfony/property-info": "^6.4|7.4.*|^8.0",
5963
"symfony/dotenv": "^6.4|7.4.*|^8.0",
6064
"symfony/runtime": "^6.4|7.4.*|^8.0",
6165
"symfony/stimulus-bundle": "^2.30",
@@ -65,7 +69,9 @@
6569
"twig/twig": "^2.12|^3.21.1",
6670
"symfony/panther": "^v2.4.0",
6771
"dbrekelmans/bdi": "^1.4",
68-
"symfony/asset-mapper": "^6.4|^7.4|^8.0"
72+
"symfony/asset-mapper": "^6.4|^7.4|^8.0",
73+
"symfony/rate-limiter": "^6.4|^7.4|^8.0",
74+
"symfony/lock": "^6.4|^7.4|^8.0"
6975
},
7076
"scripts" : {
7177
"test": [

drivers/chromedriver

18.3 MB
Binary file not shown.

drivers/geckodriver

5.85 MB
Binary file not shown.

phpunit.xml.dist

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
<!-- http://phpunit.de/manual/4.1/en/appendixes.configuration.html -->
33
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" backupGlobals="false"
44
colors="true" bootstrap="vendor/autoload.php">
5+
<php>
6+
<env name="APP_ENV" value="test" force="true" />
7+
<env name="APP_SECRET" value="s3cret" force="true" />
8+
</php>
9+
510
<testsuites>
611
<testsuite name="Ace Bundle Test Suite">
712
<directory>tests</directory>

src/DependencyInjection/AltchaExtension.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use Symfony\Component\DependencyInjection\Extension\Extension;
1111
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
1212
use Symfony\Component\DependencyInjection\Loader;
13+
use Symfony\Component\DependencyInjection\Reference;
14+
use Symfony\Component\RateLimiter\RateLimiterFactory;
1315
use Symfony\UX\StimulusBundle\StimulusBundle;
1416
use Symfony\Component\DependencyInjection\Exception\LogicException;
1517

@@ -27,6 +29,15 @@ public function load(array $configs, ContainerBuilder $container): void
2729
if ($container->getParameter('altcha.use_sentinel')) {
2830
$loader->load('services_sentinel.yml');
2931
}
32+
if ($config['rate_limiter'] !== null) {
33+
if (!class_exists(RateLimiterFactory::class)) {
34+
throw new LogicException(
35+
'symfony/rate-limiter is required to use the "rate_limiter" option. Run "composer require symfony/rate-limiter".'
36+
);
37+
}
38+
$container->getDefinition('altcha.validator')
39+
->setArgument('$rateLimiter',new Reference($config['rate_limiter']));
40+
}
3041
}
3142

3243
/**

0 commit comments

Comments
 (0)