diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 27c23a4..372f91d 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.2.0 + uses: dependabot/fetch-metadata@v3.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 41b00b9..3e724f1 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -8,7 +8,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.head_ref }} @@ -18,6 +18,6 @@ jobs: args: --config=.php-cs-fixer.php --allow-risky=yes - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Fix styling diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 0b2ec49..197e4eb 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f156e20..02e8c3a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -12,22 +12,30 @@ on: jobs: test: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest timeout-minutes: 5 strategy: fail-fast: false matrix: - os: [ubuntu-latest] - php: [8.3, 8.2] - laravel: [11.*] - stability: [prefer-stable] - testbench: [9.*] - - name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.os }} + php: ['8.2', '8.3', '8.4', '8.5'] + laravel: ['11.*', '12.*', '13.*'] + livewire: ['3.*', '4.*'] + exclude: + - laravel: '13.*' + php: '8.2' + include: + - laravel: '11.*' + testbench: '9.*' + - laravel: '12.*' + testbench: '10.*' + - laravel: '13.*' + testbench: '11.*' + + name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - Livewire ${{ matrix.livewire }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -43,8 +51,8 @@ jobs: - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update - composer update --${{ matrix.stability }} --prefer-dist --no-interaction + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "livewire/livewire:${{ matrix.livewire }}" --no-interaction --no-update + composer update --prefer-stable --prefer-dist --no-interaction - name: List Installed Dependencies run: composer show -D diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 0cdea23..8645982 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: main @@ -21,7 +21,7 @@ jobs: release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v7 with: branch: main commit_message: Update CHANGELOG diff --git a/README.md b/README.md index 4935fd5..6c91005 100755 --- a/README.md +++ b/README.md @@ -22,11 +22,12 @@ version you are going to implement. This package supports the following versions. Note that each version requires a different sitekey/secretkey pair: -| **Version** | **Docs** | **Notes** | -|----------------------|-------------------------------------------------------------------|-----------------------------| -| **v3** (recommended) | [V3 Docs](https://developers.google.com/recaptcha/docs/v3) | | -| **v2** | [V2 Docs](https://developers.google.com/recaptcha/docs/display) | | -| **v2 invisible** | [V2 Docs](https://developers.google.com/recaptcha/docs/invisible) | Use `'size' => 'invisible'` | +| **Version** | **Docs** | **Notes** | +|----------------------|-------------------------------------------------------------------|-----------------------------------| +| **v3** (recommended) | [V3 Docs](https://developers.google.com/recaptcha/docs/v3) | | +| **v3** (enterprise) | [V3 Docs](https://developers.google.com/recaptcha/docs/v3) | Use `'version' => 'v3-enterprise'` | +| **v2** | [V2 Docs](https://developers.google.com/recaptcha/docs/display) | | +| **v2 invisible** | [V2 Docs](https://developers.google.com/recaptcha/docs/invisible) | Use `'size' => 'invisible'` | Your options should reside in the `config/services.php` file: @@ -38,6 +39,7 @@ Your options should reside in the `config/services.php` file: 'secret_key' => env('GOOGLE_RECAPTCHA_SECRET_KEY'), 'version' => 'v3', 'score' => 0.5, // An integer between 0 and 1, that indicates the minimum score to pass the Captcha challenge. + 'endpoint' => 'https://www.google.com/recaptcha/api/siteverify', // For enterprise users, fill in your URL from Google Console. ], ], @@ -102,6 +104,10 @@ Secondly, add the new directive `wire:recaptcha` to the form element that you wa
+ + +
+
diff --git a/composer.json b/composer.json index 9aa9f51..553fd6e 100755 --- a/composer.json +++ b/composer.json @@ -11,12 +11,12 @@ "license": "MIT", "require": { "php": "^8.2", - "livewire/livewire": "^3.0" + "livewire/livewire": "^3.0|^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.8", - "larastan/larastan": "^2.9", - "orchestra/testbench": "^9.0", + "larastan/larastan": "^2.9|^3.0", + "orchestra/testbench": "^9.0|^10.0", "phpunit/phpunit": "^11.1" }, "autoload": { diff --git a/src/LivewireRecaptcha.php b/src/LivewireRecaptcha.php index de203cc..55d0907 100644 --- a/src/LivewireRecaptcha.php +++ b/src/LivewireRecaptcha.php @@ -15,10 +15,10 @@ class LivewireRecaptcha * @return string */ public static function directive( - string $version = null, - string $siteKey = null, - string $theme = null, - string $size = null, + ?string $version = null, + ?string $siteKey = null, + ?string $theme = null, + ?string $size = null, ): string { $version ??= config('services.google.recaptcha.version') ?? 'v3'; diff --git a/src/ValidatesRecaptcha.php b/src/ValidatesRecaptcha.php index 345e7e9..6146850 100755 --- a/src/ValidatesRecaptcha.php +++ b/src/ValidatesRecaptcha.php @@ -16,9 +16,11 @@ class ValidatesRecaptcha extends LivewireAttribute public function __construct( public ?string $secretKey = null, public ?float $score = null, + public ?string $endpoint = null, ) { $this->secretKey ??= config('services.google.recaptcha.secret_key'); $this->score ??= config('services.google.recaptcha.score') ?? 0.5; + $this->endpoint ??= config('services.google.recaptcha.endpoint', 'https://www.google.com/recaptcha/api/siteverify'); } /** @@ -28,8 +30,10 @@ public function __construct( */ public function call(array $params, Closure $returnEarly): void { + assert(is_string($this->endpoint)); + if (isset($this->component->gRecaptchaResponse)) { - $response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [ + $response = Http::asForm()->post($this->endpoint, [ 'secret' => $this->secretKey, 'response' => $this->component->gRecaptchaResponse, 'remoteip' => request()->ip(), diff --git a/src/directive.recaptcha.v3-enterprise.blade.php b/src/directive.recaptcha.v3-enterprise.blade.php new file mode 100755 index 0000000..5fe16b1 --- /dev/null +++ b/src/directive.recaptcha.v3-enterprise.blade.php @@ -0,0 +1,29 @@ + + diff --git a/tests/CaptchaTest.php b/tests/CaptchaTest.php index c3ad4ce..565bca3 100644 --- a/tests/CaptchaTest.php +++ b/tests/CaptchaTest.php @@ -2,6 +2,7 @@ namespace DutchCodingCompany\LivewireRecaptcha\Tests; +use DutchCodingCompany\LivewireRecaptcha\Tests\Fixtures\MyCustomAttributeComponent; use DutchCodingCompany\LivewireRecaptcha\Tests\Fixtures\MyTestComponent; use Illuminate\Http\Client\Request; use Illuminate\Support\Facades\Http; @@ -13,7 +14,7 @@ class CaptchaTest extends TestCase /** * @param array{0: bool, 1: array{'success': bool}} $captchaResponse */ - #[DataProvider('provideCaptchaData')] + #[DataProvider('provideDefaultAttributeData')] public function testInvalidCaptchaResponse(bool $isValid, array $captchaResponse): void { Http::fake([ @@ -45,10 +46,52 @@ public function testInvalidCaptchaResponse(bool $isValid, array $captchaResponse ); } + /** + * @param array{0: bool, 1: array{'success': bool}} $captchaResponse + */ + #[DataProvider('provideCustomAttributeData')] + public function testCustomAttributeProperties(bool $isValid, array $captchaResponse): void + { + Http::fake([ + 'https://custom.example.com/verify' => Http::response($captchaResponse), + ]); + + $testable = Livewire::test(MyCustomAttributeComponent::class) + ->set('gRecaptchaResponse', $captcha = 'mygrecaptcharesponse') + ->call('save'); + + if ($isValid) { + $testable->assertHasNoErrors(); + } else { + $testable->assertHasErrors([ + 'gRecaptchaResponse', + ]); + } + + Http::assertSent(fn (Request $request) => $request->url() === 'https://custom.example.com/verify' && + $request['secret'] === 'custom-secret-key' && + $request['response'] === $captcha && + array_key_exists('remoteip', $request->data()) + ); + } + + /** + * @return array + */ + public static function provideCustomAttributeData(): array + { + return [ + 'valid response' => [true, ['success' => true, 'score' => 0.9]], + 'valid response, score at threshold' => [true, ['success' => true, 'score' => 0.7]], + 'valid response, score below threshold' => [false, ['success' => true, 'score' => 0.5]], + 'invalid response' => [false, ['success' => false]], + ]; + } + /** * @return array */ - public static function provideCaptchaData(): array + public static function provideDefaultAttributeData(): array { return [ 'valid response' => [true, ['success' => true, 'score' => 0.9]], diff --git a/tests/Fixtures/MyCustomAttributeComponent.php b/tests/Fixtures/MyCustomAttributeComponent.php new file mode 100644 index 0000000..8850d6b --- /dev/null +++ b/tests/Fixtures/MyCustomAttributeComponent.php @@ -0,0 +1,32 @@ +