diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fdd1e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea/ +/vendor +composer.phar +composer.lock +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..52a7d02 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Papertank Limited <http://github.com/papertank> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..e6aa9c9 --- /dev/null +++ b/composer.json @@ -0,0 +1,33 @@ +{ + "name": "origami/captcha", + "description": "Simgple Google Captcha integration for Laravel projects", + "license": "MIT", + "authors": [ + { + "name": "Papertank", + "email": "hello@papertank.com" + } + ], + "require": { + "php": ">=5.6", + "illuminate/support": "~5.4", + "illuminate/validation": "~5.4", + "google/recaptcha": "^1.1" + }, + "autoload": { + "psr-4": { + "Origami\\Captcha\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Origami\\Captcha\\CaptchaServiceProvider" + ] + } + }, + "minimum-stability": "stable" +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..6c9c6d5 --- /dev/null +++ b/readme.md @@ -0,0 +1,127 @@ +# Origami Catpcha - Laravel Google ReCaptcha Integration + +This package adds a validation rule and controller trait for easier integration with Google Recaptcha + +## Installation + +Install this package through Composer. + +``` +composer require origami/captcha +``` + +### Requirements + +This package is designed to work with Laravel >= 5.4 currently. + +### Service Provider + +If you do not have package auto discovery, there is a Laravel 5 is a service provider you can make use of to automatically prepare the bindings. + +```php + +// app/config/app.php + +‘providers’ => [ + ... + Origami\Consent\ConsentServiceProvider::class +]; +``` + +### Setup + +1. Signup for a Google Recaptcha account at https://www.google.com/recaptcha/admin + +2. You should add a recatpcha section to your `config/services.php` file: + +```php + + 'recaptcha' => [ + 'key' => env('RECAPTCHA_KEY'), + 'secret' => env('RECAPTCHA_SECRET'), + ], + +``` + +3. Update your `.env` file with the key and secret: + +``` +RECAPTCHA_KEY= +RECAPTCHA_SECRET= +``` + +4. Add a language line to your validation file(s), e.g. `resources/lang/en/validation.php` + +``` + + 'recaptcha' => 'The reCAPTCHA check was invalid', + +``` + +## Usage + +### Validator + +```php +$validator = Validator::make($request->all(), [ + 'recaptcha' => 'recaptcha', +]); +``` + +### Controller Validation + +(Assuming your Controller has the `ValidatesRequests` trait) + +```php +class Contact extends Controller +{ + public function store(Request $request) + { + $this->validate($request, [ + 'recatpcha' => 'recaptcha' + ]); + } +} +``` + +### Controller with ValidatesCaptcha Trait + +```php + +use Origami\Captcha\ValidatesCaptcha; + +class Contact extends Controller +{ + use ValidatesCaptcha; + + public function store(Request $request) + { + $this->validateCatpcha($request); + + // The above will throw a ValidationException when the recaptcha fails. + } + +} +``` + +## Blade Helpers + +This packages registers two Blade helpers: + +`@recaptchaField` is the equivalent of: + +``` +<div class="g-recaptcha" data-sitekey="{{ config('services.recaptcha.key') }}"></div> +``` + +`@recaptchaScript` is the equivalent of: + +``` +<script src="https://www.google.com/recaptcha/api.js"></script> +``` + +## Author +[Papertank Limited](http://papertank.com) + +## License +[MIT License](http://github.com/papertank/origami-captcha/blob/master/LICENSE) \ No newline at end of file diff --git a/src/CaptchaServiceProvider.php b/src/CaptchaServiceProvider.php new file mode 100644 index 0000000..66677a2 --- /dev/null +++ b/src/CaptchaServiceProvider.php @@ -0,0 +1,40 @@ +<?php + +namespace Origami\Captcha; + +use Illuminate\Support\Facades\Blade; +use Illuminate\Support\ServiceProvider; +use Illuminate\Support\Facades\Validator; +use Origami\Captcha\Validation\RecaptchaValidator; + +class CaptchaServiceProvider extends ServiceProvider +{ + /** + * Indicates if loading of the provider is deferred. + * + * @var bool + */ + protected $defer = false; + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + } + + public function boot() + { + Validator::extendImplicit('recaptcha', RecaptchaValidator::class.'@validate'); + + Blade::directive('recaptchaField', function ($expression) { + return '<div class="g-recaptcha" data-sitekey="'.config('services.recaptcha.key').'"></div>'; + }); + + Blade::directive('recaptchaScript', function ($expression) { + return '<script src="https://www.google.com/recaptcha/api.js"></script>'; + }); + } +} diff --git a/src/ValidatesCaptcha.php b/src/ValidatesCaptcha.php new file mode 100644 index 0000000..1813b5b --- /dev/null +++ b/src/ValidatesCaptcha.php @@ -0,0 +1,23 @@ +<?php + +namespace Origami\Captcha; + +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Validator; +use Illuminate\Validation\ValidationException; + +trait ValidatesCaptcha +{ + public function validateReCaptcha(Request $request) + { + $validator = Validator::make($request->all(), [ + 'recaptcha' => 'recaptcha', + ]); + + if ($validator->fails()) { + throw new ValidationException($validator); + } + + return true; + } +} diff --git a/src/Validation/RecaptchaValidator.php b/src/Validation/RecaptchaValidator.php new file mode 100644 index 0000000..be77d0c --- /dev/null +++ b/src/Validation/RecaptchaValidator.php @@ -0,0 +1,30 @@ +<?php + +namespace Origami\Captcha\Validation; + +use ReCaptcha\ReCaptcha; + +class RecaptchaValidator +{ + public function validate($attribute, $value, $parameters, $validator) + { + if (app()->environment('testing')) { + return true; + } + + $recaptcha = new ReCaptcha(config('services.recaptcha.secret')); + $response = $recaptcha->verify($this->getResponse(), $this->getIp()); + + return $response->isSuccess(); + } + + protected function getResponse() + { + return app('request')->input('g-recaptcha-response'); + } + + protected function getIp() + { + return app('request')->ip(); + } +}