JFIFxxC      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbrno-captcha/composer.json000064400000001745150364326200011313 0ustar00{ "name": "anhskohbo/no-captcha", "description": "No CAPTCHA reCAPTCHA For Laravel.", "keywords": [ "recaptcha", "no-captcha", "captcha", "laravel", "laravel4", "laravel5", "laravel6" ], "license": "MIT", "authors": [ { "name": "anhskohbo", "email": "anhskohbo@gmail.com" } ], "require": { "php": ">=5.5.5", "illuminate/support": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", "guzzlehttp/guzzle": "^6.2|^7.0" }, "require-dev": { "phpunit/phpunit": "~4.8|^9.5.10" }, "autoload": { "psr-4": { "Anhskohbo\\NoCaptcha\\": "src/" } }, "extra": { "laravel": { "providers": [ "Anhskohbo\\NoCaptcha\\NoCaptchaServiceProvider" ], "aliases": { "NoCaptcha": "Anhskohbo\\NoCaptcha\\Facades\\NoCaptcha" } } } } no-captcha/tests/.gitkeep000064400000000000150364326200011343 0ustar00no-captcha/tests/NoCaptchaTest.php000064400000005573150364326200013147 0ustar00captcha = new NoCaptcha('{secret-key}', '{site-key}'); } public function testRequestShouldWorks() { $response = $this->captcha->verifyResponse('should_false'); } public function testJsLink() { $this->assertTrue($this->captcha instanceof NoCaptcha); $simple = ''."\n"; $withLang = ''."\n"; $withCallback = ''."\n"; $this->assertEquals($simple, $this->captcha->renderJs()); $this->assertEquals($withLang, $this->captcha->renderJs('vi')); $this->assertEquals($withCallback, $this->captcha->renderJs(null, true, 'myOnloadCallback')); } public function testDisplay() { $this->assertTrue($this->captcha instanceof NoCaptcha); $simple = '
'; $withAttrs = '
'; $this->assertEquals($simple, $this->captcha->display()); $this->assertEquals($withAttrs, $this->captcha->display(['data-theme' => 'light'])); } public function testdisplaySubmit() { $this->assertTrue($this->captcha instanceof NoCaptcha); $javascript = ''; $simple = ''; $withAttrs = ''; $this->assertEquals($simple . $javascript, $this->captcha->displaySubmit('test')); $withAttrsResult = $this->captcha->displaySubmit('test','submit123',['data-theme' => 'light', 'class' => '123']); $this->assertEquals($withAttrs . $javascript, $withAttrsResult); } public function testdisplaySubmitWithCustomCallback() { $this->assertTrue($this->captcha instanceof NoCaptcha); $withAttrs = ''; $withAttrsResult = $this->captcha->displaySubmit('test-custom','submit123',['data-theme' => 'light', 'class' => '123', 'data-callback' => 'onSubmitCustomCallback']); $this->assertEquals($withAttrs, $withAttrsResult); } } no-captcha/src/config/captcha.php000064400000000232150364326200012727 0ustar00 env('NOCAPTCHA_SECRET'), 'sitekey' => env('NOCAPTCHA_SITEKEY'), 'options' => [ 'timeout' => 30, ], ]; no-captcha/src/config/.gitkeep000064400000000000150364326200012235 0ustar00no-captcha/src/NoCaptcha.php000064400000014202150364326200011721 0ustar00secret = $secret; $this->sitekey = $sitekey; $this->http = new Client($options); } /** * Render HTML captcha. * * @param array $attributes * * @return string */ public function display($attributes = []) { $attributes = $this->prepareAttributes($attributes); return 'buildAttributes($attributes) . '>'; } /** * @see display() */ public function displayWidget($attributes = []) { return $this->display($attributes); } /** * Display a Invisible reCAPTCHA by embedding a callback into a form submit button. * * @param string $formIdentifier the html ID of the form that should be submitted. * @param string $text the text inside the form button * @param array $attributes array of additional html elements * * @return string */ public function displaySubmit($formIdentifier, $text = 'submit', $attributes = []) { $javascript = ''; if (!isset($attributes['data-callback'])) { $functionName = 'onSubmit' . str_replace(['-', '=', '\'', '"', '<', '>', '`'], '', $formIdentifier); $attributes['data-callback'] = $functionName; $javascript = sprintf( '', $functionName, $formIdentifier ); } $attributes = $this->prepareAttributes($attributes); $button = sprintf('%s', $this->buildAttributes($attributes), $text); return $button . $javascript; } /** * Render js source * * @param null $lang * @param bool $callback * @param string $onLoadClass * @return string */ public function renderJs($lang = null, $callback = false, $onLoadClass = 'onloadCallBack') { return ''."\n"; } /** * Verify no-captcha response. * * @param string $response * @param string $clientIp * * @return bool */ public function verifyResponse($response, $clientIp = null) { if (empty($response)) { return false; } // Return true if response already verfied before. if (in_array($response, $this->verifiedResponses)) { return true; } $verifyResponse = $this->sendRequestVerify([ 'secret' => $this->secret, 'response' => $response, 'remoteip' => $clientIp, ]); if (isset($verifyResponse['success']) && $verifyResponse['success'] === true) { // A response can only be verified once from google, so we need to // cache it to make it work in case we want to verify it multiple times. $this->verifiedResponses[] = $response; return true; } else { return false; } } /** * Verify no-captcha response by Symfony Request. * * @param Request $request * * @return bool */ public function verifyRequest(Request $request) { return $this->verifyResponse( $request->get('g-recaptcha-response'), $request->getClientIp() ); } /** * Get recaptcha js link. * * @param string $lang * @param boolean $callback * @param string $onLoadClass * @return string */ public function getJsLink($lang = null, $callback = false, $onLoadClass = 'onloadCallBack') { $client_api = static::CLIENT_API; $params = []; $callback ? $this->setCallBackParams($params, $onLoadClass) : false; $lang ? $params['hl'] = $lang : null; return $client_api . '?'. http_build_query($params); } /** * @param $params * @param $onLoadClass */ protected function setCallBackParams(&$params, $onLoadClass) { $params['render'] = 'explicit'; $params['onload'] = $onLoadClass; } /** * Send verify request. * * @param array $query * * @return array */ protected function sendRequestVerify(array $query = []) { $response = $this->http->request('POST', static::VERIFY_URL, [ 'form_params' => $query, ]); return json_decode($response->getBody(), true); } /** * Prepare HTML attributes and assure that the correct classes and attributes for captcha are inserted. * * @param array $attributes * * @return array */ protected function prepareAttributes(array $attributes) { $attributes['data-sitekey'] = $this->sitekey; if (!isset($attributes['class'])) { $attributes['class'] = ''; } $attributes['class'] = trim('g-recaptcha ' . $attributes['class']); return $attributes; } /** * Build HTML attributes. * * @param array $attributes * * @return string */ protected function buildAttributes(array $attributes) { $html = []; foreach ($attributes as $key => $value) { $html[] = $key.'="'.$value.'"'; } return count($html) ? ' '.implode(' ', $html) : ''; } } no-captcha/src/NoCaptchaServiceProvider.php000064400000003232150364326200014756 0ustar00app; $this->bootConfig(); $app['validator']->extend('captcha', function ($attribute, $value) use ($app) { return $app['captcha']->verifyResponse($value, $app['request']->getClientIp()); }); if ($app->bound('form')) { $app['form']->macro('captcha', function ($attributes = []) use ($app) { return $app['captcha']->display($attributes, $app->getLocale()); }); } } /** * Booting configure. */ protected function bootConfig() { $path = __DIR__.'/config/captcha.php'; $this->mergeConfigFrom($path, 'captcha'); if (function_exists('config_path')) { $this->publishes([$path => config_path('captcha.php')]); } } /** * Register the service provider. */ public function register() { $this->app->singleton('captcha', function ($app) { return new NoCaptcha( $app['config']['captcha.secret'], $app['config']['captcha.sitekey'], $app['config']['captcha.options'] ); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['captcha']; } } no-captcha/src/Facades/NoCaptcha.php000064400000000460150364326200013250 0ustar00 For Laravel 4 use [v1](https://github.com/anhskohbo/no-captcha/tree/v1) branch. ## Installation ``` composer require anhskohbo/no-captcha ``` ## Laravel 5 and above ### Setup **_NOTE_** This package supports the auto-discovery feature of Laravel 5.5 and above, So skip these `Setup` instructions if you're using Laravel 5.5 and above. In `app/config/app.php` add the following : 1- The ServiceProvider to the providers array : ```php Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class, ``` 2- The class alias to the aliases array : ```php 'NoCaptcha' => Anhskohbo\NoCaptcha\Facades\NoCaptcha::class, ``` 3- Publish the config file ```ssh php artisan vendor:publish --provider="Anhskohbo\NoCaptcha\NoCaptchaServiceProvider" ``` ### Configuration Add `NOCAPTCHA_SECRET` and `NOCAPTCHA_SITEKEY` in **.env** file : ``` NOCAPTCHA_SECRET=secret-key NOCAPTCHA_SITEKEY=site-key ``` (You can obtain them from [here](https://www.google.com/recaptcha/admin)) ### Usage #### Init js source With default options : ```php {!! NoCaptcha::renderJs() !!} ``` With [language support](https://developers.google.com/recaptcha/docs/language) or [onloadCallback](https://developers.google.com/recaptcha/docs/display#explicit_render) option : ```php {!! NoCaptcha::renderJs('fr', true, 'recaptchaCallback') !!} ``` #### Display reCAPTCHA Default widget : ```php {!! NoCaptcha::display() !!} ``` With [custom attributes](https://developers.google.com/recaptcha/docs/display#render_param) (theme, size, callback ...) : ```php {!! NoCaptcha::display(['data-theme' => 'dark']) !!} ``` Invisible reCAPTCHA using a [submit button](https://developers.google.com/recaptcha/docs/invisible): ```php {!! NoCaptcha::displaySubmit('my-form-id', 'submit now!', ['data-theme' => 'dark']) !!} ``` Notice that the id of the form is required in this method to let the autogenerated callback submit the form on a successful captcha verification. #### Validation Add `'g-recaptcha-response' => 'required|captcha'` to rules array : ```php $validate = Validator::make(Input::all(), [ 'g-recaptcha-response' => 'required|captcha' ]); ``` ##### Custom Validation Message Add the following values to the `custom` array in the `validation` language file : ```php 'custom' => [ 'g-recaptcha-response' => [ 'required' => 'Please verify that you are not a robot.', 'captcha' => 'Captcha error! try again later or contact site admin.', ], ], ``` Then check for captcha errors in the `Form` : ```php @if ($errors->has('g-recaptcha-response')) {{ $errors->first('g-recaptcha-response') }} @endif ``` ### Testing When using the [Laravel Testing functionality](http://laravel.com/docs/5.5/testing), you will need to mock out the response for the captcha form element. So for any form tests involving the captcha, you can do this by mocking the facade behavior: ```php // prevent validation error on captcha NoCaptcha::shouldReceive('verifyResponse') ->once() ->andReturn(true); // provide hidden input for your 'required' validation NoCaptcha::shouldReceive('display') ->zeroOrMoreTimes() ->andReturn(''); ``` You can then test the remainder of your form as normal. When using HTTP tests you can add the `g-recaptcha-response` to the request body for the 'required' validation: ```php // prevent validation error on captcha NoCaptcha::shouldReceive('verifyResponse') ->once() ->andReturn(true); // POST request, with request body including g-recaptcha-response $response = $this->json('POST', '/register', [ 'g-recaptcha-response' => '1', 'name' => 'John', 'email' => 'john@example.com', 'password' => '123456', 'password_confirmation' => '123456', ]); ``` ## Without Laravel Checkout example below: ```php verifyResponse($_POST['g-recaptcha-response'])); exit(); } ?>
display(); ?>
renderJs(); ?> ``` ## Contribute https://github.com/anhskohbo/no-captcha/pulls no-captcha/.travis.yml000064400000000376150364326200010701 0ustar00language: php dist: trusty php: - 5.5 - 5.6 - 7.0 - 7.1 - 7.2 before_script: - travis_retry composer self-update - travis_retry composer install --prefer-source --no-interaction --dev script: - composer install - vendor/bin/phpunit no-captcha/LICENSE000064400000002076150364326200007574 0ustar00The MIT License (MIT) Copyright (c) 2014 Nguyễn Văn Ánh 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-captcha/.gitignore000064400000000056150364326200010553 0ustar00/vendor composer.phar composer.lock .DS_Store no-captcha/phpunit.xml000064400000001072150364326200010773 0ustar00 ./tests/