From 7b39abcd07ef3c30948225410dfb447afb51cb3e Mon Sep 17 00:00:00 2001 From: DarkGhostHunter Date: Thu, 5 Mar 2020 20:08:25 -0300 Subject: [PATCH 1/2] Added Laravel 7 support. --- .github/workflows/php.yml | 58 ++++++ README.md | 7 +- composer.json | 20 ++- .../Middleware/InjectRecaptchaScriptTest.php | 34 ++-- tests/Middleware/ThrottleRecaptchaTest.php | 167 ++++++++++++++++++ 5 files changed, 260 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/php.yml create mode 100644 tests/Middleware/ThrottleRecaptchaTest.php diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..56296e7 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,58 @@ +name: PHP Composer + +on: + push: + pull_request: + +jobs: + test: + + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + php: [7.4, 7.3, 7.2.15] + laravel: [7.*, 6.*] + dependency-version: [prefer-lowest, prefer-stable] + include: + - laravel: 7.* + testbench: 5.* + - laravel: 6.* + testbench: 4.* + + name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }} + + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, intl + coverage: xdebug + + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ~/.composer/cache/files + key: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} + restore-keys: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer- + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-progress --no-update + composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-suggest + + - name: Run Tests + run: composer run-script test + + - name: Upload Coverage to Coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_SERVICE_NAME: github + run: | + rm -rf composer.* vendor/ + composer require cedx/coveralls + vendor/bin/coveralls build/logs/clover.xml diff --git a/README.md b/README.md index 52bc1ff..9d866ad 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,17 @@ [![Latest Version on Packagist](https://img.shields.io/packagist/v/darkghosthunter/captchavel.svg?style=flat-square)](https://packagist.org/packages/darkghosthunter/captchavel) [![License](https://poser.pugx.org/darkghosthunter/captchavel/license)](https://packagist.org/packages/darkghosthunter/larapoke) ![](https://img.shields.io/packagist/php-v/darkghosthunter/captchavel.svg) - [![Build Status](https://travis-ci.com/DarkGhostHunter/Captchavel.svg?branch=master)](https://travis-ci.com/DarkGhostHunter/Captchavel) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/Captchavel/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/Captchavel?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/9571f57106069b5f3aac/maintainability)](https://codeclimate.com/github/DarkGhostHunter/Captchavel/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/9571f57106069b5f3aac/test_coverage)](https://codeclimate.com/github/DarkGhostHunter/Captchavel/test_coverage) - + ![](https://github.com/DarkGhostHunter/Captchavel/workflows/PHP%20Composer/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/Captchavel/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/Captchavel?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/9571f57106069b5f3aac/maintainability)](https://codeclimate.com/github/DarkGhostHunter/Captchavel/maintainability) # Captchavel Easily integrate Google reCAPTCHA v3 into your Laravel application. > This is totally compatible with reCAPTCHA v2, so you can use both. Check [this GitHub comment](https://github.com/google/recaptcha/issues/279#issuecomment-445529732) about the caveats. +## Requirements + +* Laravel 6 or Laravel 7 + ## Installation You can install the package via composer: diff --git a/composer.json b/composer.json index 095de0d..0a6df2b 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,8 @@ "recaptcha", "google" ], + "minimum-stability": "dev", + "prefer-stable": true, "homepage": "https://github.com/darkghosthunter/captchavel", "license": "MIT", "type": "library", @@ -19,19 +21,19 @@ } ], "require": { - "php": "^7.1.3", + "php": "^7.2.15", "ext-json" : "*", "google/recaptcha": "^1.2", - "illuminate/config": "6.*", - "illuminate/container": "6.*", - "illuminate/http": "6.*", - "illuminate/routing": "6.*", - "illuminate/support": "6.*", - "illuminate/validation": "6.*", - "illuminate/view": "6.*" + "illuminate/config": "^6.0||^7.0", + "illuminate/container": "^6.0||^7.0", + "illuminate/http": "^6.0||^7.0", + "illuminate/routing": "^6.0||^7.0", + "illuminate/support": "^6.0||^7.0", + "illuminate/validation": "^6.0||^7.0", + "illuminate/view": "^6.0||^7.0" }, "require-dev": { - "orchestra/testbench": "4.*" + "orchestra/testbench": "^4.1||^5.0" }, "autoload": { "files": [ diff --git a/tests/Middleware/InjectRecaptchaScriptTest.php b/tests/Middleware/InjectRecaptchaScriptTest.php index 951a401..575530a 100644 --- a/tests/Middleware/InjectRecaptchaScriptTest.php +++ b/tests/Middleware/InjectRecaptchaScriptTest.php @@ -69,40 +69,44 @@ protected function getEnvironmentSetUp($app) public function testInjectsScriptAutomatically() { - $this->get('test-get') - ->assertSee('Start Captchavel Script') - ->assertSee('api.js?render=test-key&onload=captchavelCallback'); + $response = $this->get('test-get') + ->assertSee('Start Captchavel Script'); + + $this->assertStringContainsString('api.js?render=test-key&onload=captchavelCallback', $response->getContent()); } public function testDoesntInjectsOnInvalidHtml() { - $this->get('invalid-html') - ->assertDontSee('Start Captchavel Script') - ->assertDontSee('api.js?render=test-key&onload=captchavelCallback'); + $response = $this->get('invalid-html') + ->assertDontSee('Start Captchavel Script'); + + $this->assertStringNotContainsString('api.js?render=test-key&onload=captchavelCallback', $response->getContent()); } public function testDoesntInjectsOnJson() { - $this->get('json') - ->assertDontSee('Start Captchavel Script') - ->assertDontSee('api.js?render=test-key&onload=captchavelCallback'); + $response = $this->get('json') + ->assertDontSee('Start Captchavel Script'); + + $this->assertStringNotContainsString('api.js?render=test-key&onload=captchavelCallback', $response->getContent()); } public function testDoesntInjectsOnAjax() { - $this->get('test-get', [ + $response = $this->get('test-get', [ 'X-Requested-With' => 'XMLHttpRequest' ]) - ->assertDontSee('Start Captchavel Script') - ->assertDontSee('api.js?render=test-key&onload=captchavelCallback'); + ->assertDontSee('Start Captchavel Script'); + + $this->assertStringNotContainsString('api.js?render=test-key&onload=captchavelCallback', $response->getContent()); } public function testDoesntInjectsOnException() { - $response = $this->get('route-doesnt-exists-will-trigger-exception'); + $response = $this->get('route-doesnt-exists-will-trigger-exception') + ->assertDontSee('Start Captchavel Script'); - $response->assertDontSee('Start Captchavel Script') - ->assertDontSee('api.js?render=test-key&onload=captchavelCallback'); + $this->assertStringNotContainsString('api.js?render=test-key&onload=captchavelCallback', $response->getContent()); } } diff --git a/tests/Middleware/ThrottleRecaptchaTest.php b/tests/Middleware/ThrottleRecaptchaTest.php new file mode 100644 index 0000000..6c34f88 --- /dev/null +++ b/tests/Middleware/ThrottleRecaptchaTest.php @@ -0,0 +1,167 @@ + 'DarkGhostHunter\Captchavel\Facades\ReCaptcha' + ]; + } + + protected function getPackageProviders($app) + { + return ['DarkGhostHunter\Captchavel\CaptchavelServiceProvider']; + } + + /** + * Define environment setup. + * + * @param \Illuminate\Foundation\Application $app + * @return void + */ + protected function getEnvironmentSetUp($app) + { + $app['env'] = 'local'; + + $app->make('config')->set('captchavel.enable_local', true); + $app->make('config')->set('captchavel.secret', 'test-secret'); + $app->make('config')->set('captchavel.key', 'test-key'); + + $app->make('router')->get('test-get-with-middleware', function () { return 'true'; })->middleware('recaptcha'); + $app->make('router')->get('test-get', function () { return 'true'; }); + $app->make('router')->post('test-post', function () { return 'true'; })->middleware('recaptcha'); + } + + public function testSameRecaptchaInstance() + { + $mockRequester = \Mockery::mock(RequestMethod::class); + $mockRequester->shouldReceive('submit')->andReturn(json_encode([ + 'success' => true, + 'score' => 0.8, + 'action' => '/testpost', + 'challenge_ts' => Carbon::now()->toIso8601ZuluString(), + ])); + + $this->app->when(ReCaptchaFactory::class) + ->needs(RequestMethod::class) + ->give(function () use ($mockRequester) { + return $mockRequester; + }); + + $this->post('test-post', [ + '_recaptcha' => Str::random(356) + ])->assertOk(); + + $this->assertEquals(app(ReCaptcha::class), app('recaptcha')); + $this->assertEquals(app(ReCaptcha::class), recaptcha()); + $this->assertNotEquals(app(ReCaptcha::class), new ReCaptcha()); + $this->assertNotEquals(app('recaptcha'), new ReCaptcha()); + $this->assertNotEquals(recaptcha(), new ReCaptcha()); + } + + public function testRequestWithCaptchaValidates() + { + $mockRequester = \Mockery::mock(RequestMethod::class); + $mockRequester->shouldReceive('submit')->andReturn(json_encode([ + 'success' => true, + 'score' => 0.8, + 'action' => '/testpost', + 'challenge_ts' => Carbon::now()->toIso8601ZuluString(), + ])); + + $this->app->when(ReCaptchaFactory::class) + ->needs(RequestMethod::class) + ->give(function ($app) use ($mockRequester) { + return $mockRequester; + }); + + $this->post('test-post', [ + '_recaptcha' => Str::random(356) + ])->assertOk(); + } + + public function testFailsOnNonPostMethod() + { + $this->app->make('router')->get('get-route', function () { return 'true'; })->middleware('recaptcha'); + $this->app->make('router')->match(['head'], 'head-route', function () { return 'true'; })->middleware('recaptcha'); + + $response = $this->get('get-route'); + + $response->assertStatus(200); + + $response = $this->call('head', 'head-route'); + + $response->assertStatus(200); + } + + public function testFailsInvalidToken() + { + $response = $this->post('test-post', [ '_recaptcha' => ['not.string']]); + + $response->assertStatus(500); + $this->assertInstanceOf(InvalidRecaptchaException::class, $response->exception); + } + + public function testFailsInvalidRecaptcha() + { + $mockRequester = \Mockery::mock(RequestMethod::class); + $mockRequester->shouldReceive('submit')->andReturn(json_encode([ + 'success' => false, + 'score' => 0.8, + 'action' => '/testpost', + 'challenge_ts' => Carbon::now()->toIso8601ZuluString(), + ])); + + $this->app->when(ReCaptchaFactory::class) + ->needs(RequestMethod::class) + ->give(function ($app) use ($mockRequester) { + return $mockRequester; + }); + + $response = $this->post('test-post', [ '_recaptcha' => Str::random(356)]); + + $response->assertStatus(500); + $this->assertInstanceOf(FailedRecaptchaException::class, $response->exception); + } + + public function testMiddlewareAcceptsParameter() + { + $mockReCaptchaFactory = \Mockery::mock(ReCaptchaFactory::class); + $mockReCaptchaFactory->shouldReceive('setExpectedAction') + ->once() + ->andReturnSelf(); + $mockReCaptchaFactory->shouldReceive('verify') + ->once() + ->andReturn(new Response(true, [], null, null, null, 1.0, null)); + + $this->app->when(CheckRecaptcha::class) + ->needs(ReCaptchaFactory::class) + ->give(function () use ($mockReCaptchaFactory) { + return $mockReCaptchaFactory; + }); + + $this->app->make('router') + ->post('test-post', function () { + return 'reaches'; + }) + ->middleware('recaptcha:0.9'); + + $this->post('test-post', [ '_recaptcha' => Str::random(356) ]) + ->assertOk(); + } +} From d3415ab6e7e3f345a468a06e55a115738da550a9 Mon Sep 17 00:00:00 2001 From: DarkGhostHunter Date: Thu, 5 Mar 2020 20:17:51 -0300 Subject: [PATCH 2/2] Fixed testbench version for mockery. --- .github/workflows/php.yml | 2 +- src/CaptchavelServiceProvider.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 56296e7..373ece8 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -18,7 +18,7 @@ jobs: - laravel: 7.* testbench: 5.* - laravel: 6.* - testbench: 4.* + testbench: ^4.1 name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }} diff --git a/src/CaptchavelServiceProvider.php b/src/CaptchavelServiceProvider.php index a4f72f5..10b1bac 100644 --- a/src/CaptchavelServiceProvider.php +++ b/src/CaptchavelServiceProvider.php @@ -2,14 +2,14 @@ namespace DarkGhostHunter\Captchavel; -use DarkGhostHunter\Captchavel\Http\Middleware\CheckRecaptcha; -use DarkGhostHunter\Captchavel\Http\Middleware\InjectRecaptchaScript; -use DarkGhostHunter\Captchavel\Http\Middleware\TransparentRecaptcha; -use Illuminate\Contracts\Http\Kernel; use Illuminate\Http\Request; use Illuminate\Routing\Router; +use Illuminate\Contracts\Http\Kernel; use Illuminate\Support\ServiceProvider; use ReCaptcha\ReCaptcha as ReCaptchaFactory; +use DarkGhostHunter\Captchavel\Http\Middleware\CheckRecaptcha; +use DarkGhostHunter\Captchavel\Http\Middleware\TransparentRecaptcha; +use DarkGhostHunter\Captchavel\Http\Middleware\InjectRecaptchaScript; class CaptchavelServiceProvider extends ServiceProvider {