Skip to content

Commit e810565

Browse files
authored
Merge pull request #64 from tito10047/altcha-lib-20
Altcha lib 20
2 parents ee31a16 + 0697ec9 commit e810565

46 files changed

Lines changed: 2204 additions & 1541 deletions

Some content is hidden

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

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,11 @@ tools/
77
/tests/App/Webpack/node_modules/
88
/tests/App/Webpack/public/build
99
/tests/App/Webpack/yarn.lock
10+
/tests/App/AssetMapper/config/reference.php
11+
/tests/App/Floating/config/reference.php
12+
/tests/App/LiveComponent/config/reference.php
13+
/tests/App/Overlay/config/reference.php
14+
/tests/App/Twig/config/reference.php
15+
/tests/App/Webpack/config/reference.php
1016
var/cache
11-
/drivers
17+
/driver

MIGRATE.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Migration Guide: 1.0 to 2.0
2+
3+
This guide outlines the changes required to migrate from version 1.0 to 2.0 of the `altcha-bundle`.
4+
5+
## JavaScript Changes
6+
7+
The main JavaScript i18n file has been moved and updated.
8+
9+
- **Old path:** `"altcha/dist/altcha.i18n.js": "^2.0.0"`
10+
- **New path:** `"altcha/dist/main/altcha.i18n.js": "^3.0.2"`
11+
12+
### Webpack Encore Update
13+
If you are using a custom alias in `webpack.config.js`, update it as follows:
14+
15+
```js
16+
// Before
17+
module.exports.resolve.alias["altcha/dist/altcha.i18n.js"] = 'altcha/i18n';
18+
19+
// After
20+
module.exports.resolve.alias["altcha/dist/i18n/all.js"] = 'altcha/i18n';
21+
```
22+
23+
## Configuration
24+
25+
The configuration remains mostly backward compatible, but it is recommended to update to the new keys.
26+
27+
| Old Key | New Key | Status |
28+
|---------|---------|--------|
29+
| `hmacKey` | `hmacSignature` | Deprecated (fallback exists) |
30+
| `max_number` | - | Deprecated (replaced by `cost` and `counter_max`) |
31+
32+
### New Configuration Options
33+
- `hmacAlgorithm`: Specify the HMAC algorithm (default: `SHA-256`).
34+
- `hmacKeySignature`: Optional signature key.
35+
- `cost`: Challenge difficulty cost (default: `5000`).
36+
- `counter_min`: Minimum counter value (default: `5000`).
37+
- `counter_max`: Maximum counter value (default: `10000`).
38+
- `timeout`: Challenge timeout in seconds (default: `30.0`).
39+
40+
## Code Structure Changes
41+
42+
The internal architecture has been refactored to support version 2.0 of the `altcha-org/altcha` PHP library.
43+
44+
### Core Changes in `src/`
45+
- **Dependency Injection:**
46+
- `AltchaExtension` now handles `hmacSignature` instead of `hmacKey`.
47+
- **Services:**
48+
- `ChallengeResolver`: Now requires `DriverKeyProviderInterface` and handles new configuration parameters (cost, counter, timeout).
49+
- `AltchaValidator` and `AltchaSentinelValidator`: Refactored to use the new verification logic based on `Payload` and `VerifySolutionOptions`.
50+
- **New Services & Interfaces:**
51+
- `DriverKeyProviderInterface` / `DriverKeyProvider`: Centralizes algorithm selection.
52+
- `SolveChallengeResolverInterface` / `SolveChallengeResolver`: New service for verifying challenges.
53+
- **Form Type:**
54+
- `AltchaType`: Added options for `cost`, `counter_min`, `counter_max`, and `timeout`. `max_number` is now deprecated.
55+
56+
### Library Update
57+
The bundle now uses `altcha-org/altcha` v2. Key classes like `ChallengeOptions` have been replaced by `CreateChallengeOptions` or `VerifySolutionOptions`.

README.md

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ Add a config file:
4444
```yml
4545
altcha:
4646
enable: true
47-
hmacKey: '%env(APP_SECRET)%'
47+
hmacSignature: '%env(APP_SECRET)%'
48+
hmacAlgorithm: 'SHA-256'
49+
cost: 5000
50+
counter_min: 5000
51+
counter_max: 10000
52+
timeout: 30.0
4853
floating: true
4954
overlay: false
5055
use_stimulus: false
@@ -57,34 +62,6 @@ when@test:
5762
enable: false
5863
```
5964
60-
### PHP
61-
62-
`config/packages/altcha.php`:
63-
64-
```php
65-
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
66-
67-
return static function (ContainerConfigurator $containerConfigurator): void {
68-
$containerConfigurator->extension('altcha', [
69-
'enable' => true,
70-
'hmacKey' => 'RANDOM_SECRET_KEY',
71-
'floating' => true,
72-
'overlay' => true,
73-
'use_stimulus' => false,
74-
'include_script' => true,
75-
'hide_logo' => false,
76-
'hide_footer' => false
77-
]);
78-
79-
if ('test' === $containerConfigurator->env()) {
80-
// Disable captcha in test environment
81-
$containerConfigurator->extension('altcha', [
82-
'enable' => false,
83-
]);
84-
}
85-
};
86-
```
87-
8865
Import bundle routes:
8966
9067
### YML
@@ -95,12 +72,6 @@ altcha:
9572
type: yaml
9673
```
9774
98-
### PHP
99-
100-
```php
101-
$routingConfigurator->import('@AltchaBundle/config/routes.yml');
102-
```
103-
10475
⚠️ **Important – Security Configuration**
10576
10677
If your application restricts access globally using a rule like:
@@ -171,7 +142,7 @@ class ContactType extends AbstractType
171142
```js
172143
//webpack.config.js
173144
module.exports = Encore.getWebpackConfig();
174-
module.exports.resolve.alias["altcha/dist/altcha.i18n.js"]='altcha/i18n';
145+
module.exports.resolve.alias["altcha/dist/i18n/all.js"]='altcha/i18n';
175146
```
176147
```yaml
177148
#config/packages/altcha.yaml
Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,48 @@
11
import {Controller} from '@hotwired/stimulus';
2-
import 'altcha/dist/altcha.i18n.js';
2+
import 'altcha/dist/main/altcha.i18n.js';
33

44
export default class extends Controller {
55

6-
static targets = ["input","altcha"]
6+
static targets = ["input", "altcha"];
7+
static values = {
8+
hideLogo: Boolean,
9+
hideFooter: Boolean,
10+
useSentinel: Boolean,
11+
overlayContent: String,
12+
challengeUrl: String,
13+
}
714

815
connect() {
916
this.altchaTarget.addEventListener('statechange', (ev) => {
1017
if (ev.detail.state === 'verified') {
1118
this.inputTarget.value = ev.detail.payload;
12-
this.inputTarget.dispatchEvent(new Event('change', { bubbles: true }));
19+
this.inputTarget.dispatchEvent(new Event('change', {bubbles: true}));
1320
}
1421
});
22+
23+
const config = {};
24+
25+
if (this.hasHideLogoValue) {
26+
config.hideLogo = this.hideLogoValue;
27+
}
28+
if (this.hasHideFooterValue) {
29+
config.hideFooter = this.hideFooterValue;
30+
}
31+
if (this.hasUseSentinelValue) {
32+
config.useSentinel = this.useSentinelValue;
33+
config.fetch = this.altchaChallengeFetchWithFallback.bind(this);
34+
}
35+
if (this.hasOverlayContentValue) {
36+
config.overlayContent = this.overlayContentValue;
37+
}
38+
this.altchaTarget.configure(config);
39+
}
40+
41+
async altchaChallengeFetchWithFallback(url, init) {
42+
try {
43+
return await fetch(url, init);
44+
} catch (e) {
45+
return await fetch(this.challengeUrlValue, init);
46+
}
1547
}
1648
}

assets/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"importmap": {
1616
"@hotwired/stimulus": "^3.0.0",
17-
"altcha/dist/altcha.i18n.js": "^2.0.0"
17+
"altcha/dist/main/altcha.i18n.js": "^3.0.2"
1818
}
1919
},
2020
"peerDependencies": {

composer.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@
2828
],
2929
"require": {
3030
"php": ">=8.2",
31-
"altcha-org/altcha": "^v1.3.1",
32-
"symfony/console": "^6.4|^7.3|^7.4|^8.0",
33-
"symfony/form": "^6.4|^7.3|^7.4|^8.0",
34-
"symfony/framework-bundle": "^6.4|^7.3|^7.4|^8.0",
35-
"symfony/http-client": "^6.4|^7.3|^7.4|^8.0",
36-
"symfony/translation": "^6.4|^7.3|^7.4|^8.0",
37-
"symfony/twig-bundle": "^6.4|^7.3|^7.4|^8.0",
38-
"symfony/validator": "^6.4|^7.3|^7.4|^8.0",
39-
"symfony/yaml": "^6.4|^7.3|^7.4|^8.0"
31+
"altcha-org/altcha": "^v2.0",
32+
"symfony/console": "^6.4|^7.4|^8.0",
33+
"symfony/form": "^6.4|^7.4|^8.0",
34+
"symfony/framework-bundle": "^6.4|^7.4|^8.0",
35+
"symfony/http-client": "^6.4|^7.4|^8.0",
36+
"symfony/translation": "^6.4|^7.4|^8.0",
37+
"symfony/twig-bundle": "^6.4|^7.4|^8.0",
38+
"symfony/validator": "^6.4|^7.4|^8.0",
39+
"symfony/yaml": "^6.4|^7.4|^8.0"
4040
},
4141
"autoload": {
4242
"psr-4": {
@@ -65,7 +65,7 @@
6565
"twig/twig": "^2.12|^3.21.1",
6666
"symfony/panther": "^v2.4.0",
6767
"dbrekelmans/bdi": "^1.4",
68-
"symfony/asset-mapper": "^6.4|^7.3|^7.4|^8.0"
68+
"symfony/asset-mapper": "^6.4|^7.4|^8.0"
6969
},
7070
"scripts" : {
7171
"test": [

config/services.yml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@ services:
1515
$useSentinel: '%altcha.use_sentinel%'
1616
$challengeUrl: '%altcha.sentinel.challenge_url%'
1717
$includeScript: '%altcha.include_script%'
18+
$cost: '%altcha.cost%'
19+
$counterMin: '%altcha.counter_min%'
20+
$counterMax: '%altcha.counter_max%'
21+
$timeout: '%altcha.timeout%'
1822
$router: '@router'
1923
altcha.validator:
2024
class: Tito10047\AltchaBundle\Validator\AltchaValidator
2125
tags: ['validator.constraint_validator']
2226
arguments:
2327
$enable: '%altcha.enable%'
24-
$hmacKey: '%altcha.hmacKey%'
28+
$hmacSignature: '%altcha.hmacSignature%'
29+
$hmacKeySignature: '%altcha.hmacKeySignature%'
2530
$requestStack: '@request_stack'
31+
$driverKeyProvider: '@Tito10047\AltchaBundle\Service\DriverKeyProviderInterface'
32+
$solveChallengeResolver: '@Tito10047\AltchaBundle\Service\SolveChallengeResolverInterface'
33+
$challengeOptionResolver: '@Tito10047\AltchaBundle\Service\ChallengeResolverInterface'
2634
Tito10047\AltchaBundle\Controller\AltchaChallengeController:
2735
public: true
2836
autowire: true
@@ -32,6 +40,22 @@ services:
3240
Tito10047\AltchaBundle\Service\ChallengeResolverInterface:
3341
class: Tito10047\AltchaBundle\Service\ChallengeResolver
3442
arguments:
35-
$hmacKey: '%altcha.hmacKey%'
36-
$expires: '%altcha.expires%'
37-
$maxNumber: '%altcha.max_number%'
43+
$driverKeyProvider: '@Tito10047\AltchaBundle\Service\DriverKeyProviderInterface'
44+
$hmacSignature: '%altcha.hmacSignature%'
45+
$hmacKeySignature: '%altcha.hmacKeySignature%'
46+
$cost: '%altcha.cost%'
47+
$counterMin: '%altcha.counter_min%'
48+
$counterMax: '%altcha.counter_max%'
49+
$expiresAt: '%altcha.expires%'
50+
Tito10047\AltchaBundle\Service\SolveChallengeResolverInterface:
51+
class: Tito10047\AltchaBundle\Service\SolveChallengeResolver
52+
arguments:
53+
$challengeResolver: '@Tito10047\AltchaBundle\Service\ChallengeResolverInterface'
54+
$hmacSignature: '%altcha.hmacSignature%'
55+
$hmacKeySignature: '%altcha.hmacKeySignature%'
56+
$timeout: '%altcha.timeout%'
57+
58+
Tito10047\AltchaBundle\Service\DriverKeyProviderInterface:
59+
class: Tito10047\AltchaBundle\Service\DriverKeyProvider
60+
arguments:
61+
$hmacAlgorithm: '%altcha.hmacAlgorithm%'

src/DependencyInjection/AltchaExtension.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ private function registerAceEditorParameters(array $config, ContainerBuilder $co
4545
$container->setParameter('altcha.floating', $config['floating']);
4646
$container->setParameter('altcha.overlay', $config['overlay']['enabled']);
4747
$container->setParameter('altcha.overlay_content', $config['overlay']['content']);
48-
$container->setParameter('altcha.hmacKey', $config['hmacKey']);
48+
$container->setParameter('altcha.hmacSignature', $config['hmacSignature']);
49+
$container->setParameter('altcha.hmacAlgorithm', $config['hmacAlgorithm']);
50+
$container->setParameter('altcha.hmacKeySignature', $config['hmacKeySignature']);
51+
$container->setParameter('altcha.cost', $config['cost']);
52+
$container->setParameter('altcha.counter_min', $config['counter_min']);
53+
$container->setParameter('altcha.counter_max', $config['counter_max']);
54+
$container->setParameter('altcha.timeout', $config['timeout']);
4955
$container->setParameter('altcha.hide_logo', $config['hide_logo']);
5056
$container->setParameter('altcha.hide_footer', $config['hide_footer']);
5157
$container->setParameter('altcha.js_path', $config['altcha_js_path']);

src/DependencyInjection/Configuration.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ public function getConfigTreeBuilder(): TreeBuilder
2121

2222
// @phpstan-ignore-next-line
2323
$rootNode
24+
->beforeNormalization()
25+
->ifTrue(static fn($v): bool => \is_array($v) && isset($v['hmacKey']) && !isset($v['hmacSignature']))
26+
->then(static function ($v): array {
27+
$v['hmacSignature'] = $v['hmacKey'];
28+
return $v;
29+
})
30+
->end()
2431
->children()
2532
->booleanNode('enable')->defaultTrue()->end()
2633
->booleanNode('floating')->defaultFalse()->end()
@@ -41,7 +48,14 @@ public function getConfigTreeBuilder(): TreeBuilder
4148
->end()
4249
->end() // end arrayNode('overlay')
4350
->booleanNode('use_stimulus')->defaultNull()->end()
44-
->integerNode('max_number')->defaultValue(100000)->end()
51+
->integerNode('cost')->defaultValue(5000)->end()
52+
->integerNode('counter_min')->defaultValue(5000)->end()
53+
->integerNode('counter_max')->defaultValue(10000)->end()
54+
->floatNode('timeout')->defaultValue(30.0)->end()
55+
->integerNode('max_number')
56+
->setDeprecated('tito10047/altcha-bundle', '1.1', 'The "%node%" option is deprecated and will be removed.')
57+
->defaultValue(100000)
58+
->end()
4559
->scalarNode('expires')
4660
->defaultValue('+15 minute')
4761
->cannotBeEmpty()
@@ -53,9 +67,21 @@ public function getConfigTreeBuilder(): TreeBuilder
5367
->booleanNode('include_script')->defaultNull()->end()
5468
->booleanNode('hide_logo')->defaultFalse()->end()
5569
->booleanNode('hide_footer')->defaultFalse()->end()
56-
->scalarNode('altcha_js_path')->defaultValue('https://eu.altcha.org/js/latest/altcha.min.js')->end()
57-
->scalarNode('altcha_js_i18n_path')->defaultValue('https://cdn.jsdelivr.net/gh/altcha-org/altcha/dist_i18n/all.min.js')->end()
58-
->scalarNode('hmacKey')->isRequired()->cannotBeEmpty()->end()
70+
->scalarNode('altcha_js_path')->defaultValue('https://cdn.jsdelivr.net/npm/altcha/dist/main/altcha.min.js')->end()
71+
->scalarNode('altcha_js_i18n_path')->defaultValue('https://cdn.jsdelivr.net/npm/altcha/dist/i18n/all.min.js')->end()
72+
->scalarNode('hmacKey')
73+
->setDeprecated('tito10047/altcha-bundle', '1.1', 'The "%node%" option is deprecated, use "hmacSignature" instead.')
74+
->defaultValue(null)
75+
->end()
76+
->scalarNode('hmacAlgorithm')
77+
->defaultValue('SHA-256')
78+
->validate()
79+
->ifNotInArray(['SHA-256', 'SHA-384', 'SHA-512'])
80+
->thenInvalid('Invalid HMAC algorithm "%s". Permitted values are SHA-256, SHA-384, SHA-512.')
81+
->end()
82+
->end()
83+
->scalarNode('hmacSignature')->isRequired()->cannotBeEmpty()->end()
84+
->scalarNode('hmacKeySignature')->defaultNull()->end()
5985
->arrayNode('sentinel')->info(<<<TXT
6086
Enable usage of sentinel, if enabled:
6187
- the widget will use the /v1/challenge endpoint to retrieve a new challenge instead of your app;

0 commit comments

Comments
 (0)