[
  {
    "path": ".editorconfig",
    "content": "[*]\ncharset=utf-8\nend_of_line=lf\ninsert_final_newline=false\nindent_style=space\nindent_size=4\n\n[{*.yml,*.yaml}]\nindent_style=space\nindent_size=2\n\n"
  },
  {
    "path": ".gitattributes",
    "content": "/tests export-ignore\n/.github export-ignore\n/.gitattributes export-ignore\n/.gitignore export-ignore\n/.scrutinizer.yml export-ignore\n/.travis.yml export-ignore\n/.editorconfig export-ignore\n/phpunit.xml export-ignore\n/changelog.md export-ignore\n/README.md export-ignore\n/CONTRIBUTING.md export-ignore\n/CODE_OF_CONDUCT.md export-ignore"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Environment:**\n - OS and server: [e.g. Ubuntu 16.04 / Nginx] (If you are using a VM on Windows DON'T \"say\" Windows)\n - PHP version [7.1.x]\n - Laravel version [e.g. 5.5]\n - Package version [e.g. 3.4.1]\n\n**Additional context**\nAdd any other context about the problem here, like code snippets.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md",
    "content": "Bug Fixes **ONLY**. NO NEW FEATURE ACCEPTED!\n\n<!--- Provide a general summary of your changes in the Title above -->\n\n## Description\n<!--- Describe your changes in detail -->\n\n## Related Issue\n<!--- This project only accepts pull requests related to open issues -->\n<!--- If suggesting a new feature or change, please discuss it in an issue first -->\n<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->\n<!--- Please link to the issue here: -->\n\n## Motivation and Context\n<!--- Why is this change required? What problem does it solve? -->\n<!--- If it fixes an open issue, please link to the issue here. -->\n\n## How Has This Been Tested?\n<!--- Please describe in detail how you tested your changes. -->\n<!--- Include details of your testing environment, and the tests you ran to -->\n<!--- see how your change affects other areas of the code, etc. -->\n\n## Screenshots (if appropriate):\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  - push\n  - pull_request\n\njobs:\n  run:\n    runs-on: ${{ matrix.os }}\n\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n        php: [7.3, 7.4, '8.0', 8.1, '8.2']\n        laravel: [7, 8, 9, 10, '11']\n        exclude:\n          - php: 7.3\n            laravel: 10\n          - php: 7.4\n            laravel: 10\n          - php: 8.0\n            laravel: 10\n          - php: 7.3\n            laravel: 9\n          - php: 7.4\n            laravel: 9\n          - laravel: '11'\n            php: 7.3\n          - laravel: '11'\n            php: 7.4\n          - laravel: '11'\n            php: '8.0'\n          - laravel: '11'\n            php: 8.1\n\n    name: PHP ${{ matrix.php }} Test on ${{ matrix.os }} – Laravel ${{ matrix.laravel }}\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{matrix.php}}\n\n      - name: Install dependencies\n        uses: php-actions/composer@v5\n        with:\n          args: --prefer-source --no-interaction\n\n      - name: Run composer test script\n        uses: php-actions/composer@v5\n        with:\n          command: test\n"
  },
  {
    "path": ".gitignore",
    "content": "vendor/\n/.idea\n\n# Rocketeer PHP task runner and deployment package. https://github.com/rocketeers/rocketeer\n.rocketeer/\n\n# composer\n/composer.lock\n/composer.local.*\n/composer.phar\n\n# coverage reports\n/coverage.clover\ncoverage.xml\nclover.xml\nreport/\n\n# testing\n.phpunit.result.cache\nphpunit.xml.dist.bak"
  },
  {
    "path": ".scrutinizer.yml",
    "content": "build:\n  nodes:\n    coverage:\n      tests:\n        override:\n          - command: vendor/bin/phpunit --coverage-clover=clover.xml\n            coverage:\n              file: clover.xml\n              format: clover\ntools:\n    php_code_sniffer:\n        config:\n            standard: PSR2"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\n\nphp:\n  - 7.3\n  - 7.4\n  - 8.0\n# PHP 8.1 isn't currently support by Travis CI\n#  - 8.1\n\nenv:\n  - ILLUMINATE_VERSION=^7.0 TESTBENCH_VERSION=5.*\n  - ILLUMINATE_VERSION=^8.0 TESTBENCH_VERSION=6.*\n  - ILLUMINATE_VERSION=^9.0 TESTBENCH_VERSION=^7.0\n\nmatrix:\n  exclude:\n    # Don't test Laravel 9 on PHP 7.3 or PHP 7.4, as the mininmum\n    # required PHP version for this Laravel version is 8.0.2\n    - php: 7.3\n      env: ILLUMINATE_VERSION=^9.0 TESTBENCH_VERSION=^7.0\n    - php: 7.4\n      env: ILLUMINATE_VERSION=^9.0 TESTBENCH_VERSION=^7.0\n\nbefore_install:\n  - composer require \"illuminate/routing:${ILLUMINATE_VERSION}\" --no-update --prefer-dist\n  - composer require \"illuminate/support:${ILLUMINATE_VERSION}\" --no-update --prefer-dist\n  - composer require \"orchestra/testbench:${TESTBENCH_VERSION}\" --no-update --prefer-dist\n\ninstall: travis_retry composer install --prefer-source --no-interaction\n\nscript:\n  - composer test\n\nfast_finish: true\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at roby.belotti@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nContributions are **welcome** and will be fully **credited**.\n\nWe accept contributions via Pull Requests on [Github](https://github.com/biscolab/laravel-recaptcha).\n\n\n## Pull Requests\n\n- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).\n\n- **Add tests!** - Your patch won't be accepted if it doesn't have tests.\n\n- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.\n\n- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.\n\n- **Create feature branches** - Don't ask us to pull from your master branch.\n\n- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.\n\n- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.\n\n\n## Running Tests\n\n``` bash\n$ composer test\n```\n\n\n**Happy coding**!\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 - present Roberto Belotti\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "**Laravel ReCAPTCHA** is a very simply-to-use Laravel 5 package to embed Google reCAPTCHA in your application.\n\n[![Build Status](https://travis-ci.org/biscolab/laravel-recaptcha.svg?branch=master#img-thumbnail)](https://travis-ci.org/biscolab/laravel-recaptcha)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/biscolab/laravel-recaptcha/badges/quality-score.png?b=master#img-thumbnail)](https://scrutinizer-ci.com/g/biscolab/laravel-recaptcha/?branch=master)\n[![Code Coverage](https://scrutinizer-ci.com/g/biscolab/laravel-recaptcha/badges/coverage.png?b=master#img-thumbnail)](https://scrutinizer-ci.com/g/biscolab/laravel-recaptcha/?branch=master)\n[![Packagist version](https://img.shields.io/packagist/v/biscolab/laravel-recaptcha.svg#img-thumbnail)](https://packagist.org/packages/biscolab/laravel-recaptcha)\n[![Downloads](https://img.shields.io/packagist/dt/biscolab/laravel-recaptcha.svg#img-thumbnail)](https://packagist.org/packages/biscolab/laravel-recaptcha/stats)\n[![MIT License](https://img.shields.io/github/license/biscolab/laravel-recaptcha.svg#img-thumbnail)](https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE)\n\n## What is reCAPTCHA?\n\nGoogle developers says: \"reCAPTCHA protects you against spam and other types of automated abuse. Here, we explain how to add reCAPTCHA to your site or application.\"\n\nYou can find further info at <a href=\"https://developers.google.com/recaptcha/intro\" target=\"_blank\" title=\"Google reCAPTCHA Developer's Guide\">Google reCAPTCHA Developer's Guide</a>\n\n## reCAPTCHA available versions\n\nAt this moment there are 3 versions available (for web applications):\n\n- **v3**, the latest (<a href=\"https://developers.google.com/recaptcha/docs/v3\" target=\"_blank\">reCAPTCHA v3</a>)\n- **v2 checkbox** or simply reCAPTCHA v2 (<a href=\"https://developers.google.com/recaptcha/docs/display\" target=\"_blank\">reCAPTCHA v2</a>)\n- **v2 invisible** (<a href=\"https://developers.google.com/recaptcha/docs/invisible\" target=\"_blank\">Invisible reCAPTCHA</a>)\n\n## Get your key first!\n\nFirst of all you have to create your own API keys <a href=\"https://www.google.com/recaptcha/admin\" target=\"_blank\">here</a>\n\nFollow the instructions and at the end of the process you will find **Site key** and **Secret key**. Keep them close..you will need soon!\n\n## System requirements\n\n| Package version | reCaptcha version             | PHP version           | Laravel version         | \n| --------------- | ----------------------------- | --------------------- | ----------------------- | \n| 6.1             | v3, v2 Invisible, v2 Checkbox | 7.3 or greater        | 7, 8, 9, 10, 11         | \n| 6.0             | v3, v2 Invisible, v2 Checkbox | 7.3 or greater        | 7, 8, 9, 10             | \n| 5.x             | v3, v2 Invisible, v2 Checkbox | 7.3 or greater        | 7, 8, 9                 | \n| 4.2.x to 4.4.x  | v3, v2 Invisible, v2 Checkbox | 7.1 or greater        | 5.5 or greater, 6, 7, 8 | \n| 4.1.x           | v3, v2 Invisible, v2 Checkbox | 7.1 or greater        | 5.5 or greater, 6, 7    | \n| 4.0.x           | v3, v2 Invisible, v2 Checkbox | 7.1 or greater        | 5.5 or greater, 6       | \n| 3.x             | v3, v2 Invisible, v2 Checkbox | 7.1 or greater        | 5.5 or greater, 6 (\\*)  | \n| 2.x             | v2 Invisible, v2 Checkbox     | 5.5.9, 7.0 or greater | 5.0 or greater          | \n\n> (\\*) Version 3.6.1 is Laravel 6 ready\n\n## Composer\n\nYou can install the package via composer:\n\n```sh\n$ composer require biscolab/laravel-recaptcha\n```\n\nLaravel 5.5 (or greater) uses package auto-discovery, so doesn't require you to manually add the Service Provider, but if you don't use auto-discovery `ReCaptchaServiceProvider` must be registered in `config/app.php`:\n\n```php\n'providers' => [\n    ...\n    Biscolab\\ReCaptcha\\ReCaptchaServiceProvider::class,\n];\n```\n\nYou can use the facade for shorter code. Add `ReCaptcha` to your aliases:\n\n```php\n'aliases' => [\n    ...\n    'ReCaptcha' => Biscolab\\ReCaptcha\\Facades\\ReCaptcha::class,\n];\n```\n\n\n## Publish package\n\nCreate `config/recaptcha.php` configuration file using the following artisan command:\n\n```sh\n$ php artisan vendor:publish --provider=\"Biscolab\\ReCaptcha\\ReCaptchaServiceProvider\"\n```\n\n## Set the environment\n\n### Add your API Keys\n\nOpen `.env` file and set `RECAPTCHA_SITE_KEY` and `RECAPTCHA_SECRET_KEY`:\n\n```php\n# in your .env file\nRECAPTCHA_SITE_KEY=<YOUR_API_SITE_KEY>\nRECAPTCHA_SECRET_KEY=<YOUR_API_SECRET_KEY>\nRECAPTCHA_SKIP_IP=<YOUR_IP_LIST>\n```\n\n`RECAPTCHA_SKIP_IP` (since v5.2.0, not required, CSV format ) allows you to add a list of IP/CIDR (netmask included).\nIt will be the value of `skip_ip`\n\n> **The following environment variables have been removed!!!**\n> Now only sensitive informations as API keys are allowed as environment variables, that means you have to set configuration values in `config/recaptcha.php`\n\n- ~~RECAPTCHA_DEFAULT_VERSION~~\n- ~~RECAPTCHA_CURL_TIMEOUT~~\n- ~~RECAPTCHA_DEFAULT_VALIDATION_ROUTE~~\n- ~~RECAPTCHA_DEFAULT_TOKEN_PARAMETER_NAME~~\n- ~~RECAPTCHA_DEFAULT_LANGUAGE~~\n\n### Complete configuration\n\nOpen `config/recaptcha.php` configuration file and set `version`:\n\n```php\nreturn [\n    'api_site_key'                  => env('RECAPTCHA_SITE_KEY', ''),\n    'api_secret_key'                => env('RECAPTCHA_SECRET_KEY', ''),\n    // changed in v4.0.0\n    'version'                       => 'v2', // supported: \"v3\"|\"v2\"|\"invisible\"\n    // @since v3.4.3 changed in v4.0.0\n    'curl_timeout'                  => 10,\n    'skip_ip'                       => env('RECAPTCHA_SKIP_IP', []), // array of IP addresses - String: dotted quad format e.g.: \"127.0.0.1\", IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed\n    // @since v3.2.0 changed in v4.0.0\n    'default_validation_route'      => 'biscolab-recaptcha/validate',\n    // @since v3.2.0 changed in v4.0.0\n    'default_token_parameter_name' => 'token',\n    // @since v3.6.0 changed in v4.0.0\n    'default_language'             => null,\n    // @since v4.0.0\n    'default_form_id'              => 'biscolab-recaptcha-invisible-form', // Only for \"invisible\" reCAPTCHA\n    // @since v4.0.0\n    'explicit'                     => false, // true|false\n    // @since v4.3.0\n    'api_domain'                   => \"www.google.com\", // default value is \"www.google.com\"\n    // @since v5.1.0\n    'empty_message'                => false,\n    // @since v5.1.0\n    'error_message_key'            => 'validation.recaptcha',\n    // @since v4.0.0\n    'tag_attributes'               => [\n        'theme'                    => 'light', // \"light\"|\"dark\"\n        'size'                     => 'normal', // \"normal\"|\"compact\"\n        'tabindex'                 => 0,\n        'callback'                 => null, // DO NOT SET \"biscolabOnloadCallback\"\n        'expired-callback'         => null, // DO NOT SET \"biscolabOnloadCallback\"\n        'error-callback'           => null, // DO NOT SET \"biscolabOnloadCallback\"\n    ]\n];\n```\n\n| Key                                 | Type                    | Description                                                                                                                                                                                                                                                      | Default                               |\n| ----------------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |\n| `api_site_key` and `api_secret_key` | `string`                | reCAPTCHA keys you have to create in order to perform Google API authentication. For more information about Site Key and Secret Key please visit [Google reCAPTCHA developer documentation](https://developers.google.com/recaptcha/docs/start)                  | `''`                                  |\n| `version`                           | `string`                | indicates the reCAPTCHA version (supported: v3&#124;v2&#124;invisible). Get more info about reCAPTCHA version at <a href=\"https://developers.google.com/recaptcha/docs/versions\" target=\"_blank\">https://developers.google.com/recaptcha/docs/versions</a>       | `'v2'`                                |\n| `curl_timeout`                      | `int`                   | the maximum number of seconds to allow cURL functions to execute                                                                                                                                                                                                 | `10`                                  |\n| `skip_ip`                           | `array` &#124; `string` | a whitelist of IP addresses (array or CSV) that, if recognized, disable the reCAPTCHA validation (return always true) and if you embed JS code in blade (view) file **NO validation call will be performed**                                                     | `[]`                                  |\n| `default_validation_route`          | `string`                | the route called via javascript built-in validation script (v3 only)                                                                                                                                                                                             | `'biscolab-recaptcha/validate'`       |\n| `default_token_parameter_name`      | `string`                | the name of \"token\" GET parameter sent to `default_validation_route` to be validated (v3 only)                                                                                                                                                                   | `'token'`                             |\n| `default_language`                  | `string`                | the default language code. It has no effect with v3. See [https://developers.google.com/recaptcha/docs/language](https://developers.google.com/recaptcha/docs/language) for further information                                                                  | `null`                                |\n| `default_form_id`                   | `string`                | the default form ID. Only for \"invisible\" reCAPTCHA                                                                                                                                                                                                              | `'biscolab-recaptcha-invisible-form'` |\n| `explicit`                          | `bool`                  | deferring the render can be achieved by specifying your onload callback function and adding parameters to the JavaScript resource. It has no effect with v3 and invisible (supported values: true&#124;false)                                                    | `false`                               |\n| `api_domain`                        | `string`                | customize API domain. Default value is `'www.google.com'`, but, if not accessible you ca set that value to `'www.recaptcha.net'`. More info about [Can I use reCAPTCHA globally?](https://developers.google.com/recaptcha/docs/faq#can-i-use-recaptcha-globally) | `'www.google.com'`                    |\n| `empty_message`                     | `bool`                  | set default error message to `null`                                                                                                                                                                                                                              | `false`                               |\n| `error_message_key`                 | `string`                | set default error message translation key                                                                                                                                                                                                                        | `'validation.recaptcha'`              |\n\n#### (array) tag_attributes\n\n| Key                               | Type     | Description                                                                                                                                                                                                                                                          | Default    |\n| --------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |\n| `tag_attributes.theme`            | `string` | the color theme of the widget. (supported values: \"light\"&#124;\"dark\")                                                                                                                                                                                               | `'light'`  |\n| `tag_attributes.size`             | `string` | the size of the widget. (supported values: \"normal\"&#124;\"compact\")                                                                                                                                                                                                  | `'normal'` |\n| `tag_attributes.tabindex`         | `int`    | the tabindex of the widget and challenge                                                                                                                                                                                                                             | `0`        |\n| `tag_attributes.callback`         | `string` | the name of your callback function, executed when the user submits a successful response. The g-recaptcha-response token is passed to your callback                                                                                                                  | `null`     |\n| `tag_attributes.expired-callback` | `string` | the name of your callback function, executed when the reCAPTCHA response expires and the user needs to re-verify                                                                                                                                                     | `null`     |\n| `tag_attributes.error-callback`   | `string` | the name of your callback function, executed when reCAPTCHA encounters an error (usually network connectivity) and cannot continue until connectivity is restored. If you specify a function here, you are responsible for informing the user that they should retry | `null`     |\n\n> DO NOT SET `tag_attributes.callback`, `tag_attributes.expired-callback`, `tag_attributes.error-callback` to `biscolabOnloadCallback`. `biscolabOnloadCallback` is the default JavaScript callback function called when **explicit** is set to `true` and widget `onload` event is fired.\n\nHere you can find further details about `tag_attributes.*` [https://developers.google.com/recaptcha/docs/display#render_param](https://developers.google.com/recaptcha/docs/display#render_param)\n\n### Reload config cache file\n\n> **!!! IMPORTANT !!!** Every time you change some configuration run the following shell command:\n\n```sh\n$ php artisan config:cache\n```\n\n## Have you updated?\n\nIf you are migrating from an older version check your `config/recaptcha.php` configuration file and compare it with <a href=\"https://github.com/biscolab/laravel-recaptcha/blob/master/config/recaptcha.php\" target=\"_blank\">https://github.com/biscolab/laravel-recaptcha/blob/master/config/recaptcha.php</a>.\n\n> Make sure `config/recaptcha.php` is updated\n\n## Customize error message\n\nJust for v2 and invisible users.\n\nBefore starting please add the validation message to `resources/lang/[LANG]/validation.php` file\n\n```php\nreturn [\n    ...\n    'recaptcha' => 'Hey!!! :attribute is wrong!',\n];\n```\n\n## Embed in Blade\n\nInsert `htmlScriptTagJsApi()` helper before closing `</head>` tag.\n\nYou can also use `ReCaptcha::htmlScriptTagJsApi()`.\n\n```blade\n<!DOCTYPE html>\n<html>\n    <head>\n        ...\n        {!! htmlScriptTagJsApi($configuration) !!}\n    </head>\n```\n\n#### htmlScriptTagJsApi\n\n`htmlScriptTagJsApi` function accepts `$configuration` argument. `$configuration` has different keys depending on which ReCAPTCHA you are using:\n\n- [Checkbox](#recaptcha-v2-checkbox)\n- [Invisible](#recaptcha-v2-invisible)\n\n### ReCAPTCHA v2 Checkbox\n\n#### htmlScriptTagJsApi(\\$configuration)\n\n`$configuration` argument can have following keys:\n\n- `lang` set reCAPTCHA language. This will override `default_language` in `config/recaptcha.php`. Here you ca find the complete list of availeble languages [https://developers.google.com/recaptcha/docs/language](https://developers.google.com/recaptcha/docs/language)\n\n#### Form set-up\n\nAfter you have to insert `htmlFormSnippet()` helper inside the form where you want to use the field `g-recaptcha-response`.\n\nYou can also use `ReCaptcha::htmlFormSnippet()` .\n\n```blade\n<form>\n    @csrf\n\n    ...\n    {!! htmlFormSnippet() !!}\n    <!-- OR -->\n    {!! htmlFormSnippet($attributes) !!}\n    <input type=\"submit\">\n</form>\n```\n\n> DO NOT forget `@csrf` blade directive\n\n#### htmlFormSnippet([, array \\$attributes = [] ])\n\n`htmlFormSnippet()` function does not require attributes but you can override default config `data-` attributes:\n\n```php\n{!! htmlFormSnippet([\n    \"theme\" => \"light\",\n    \"size\" => \"normal\",\n    \"tabindex\" => \"3\",\n    \"callback\" => \"callbackFunction\",\n    \"expired-callback\" => \"expiredCallbackFunction\",\n    \"error-callback\" => \"errorCallbackFunction\",\n]) !!}\n```\n\n`htmlFormSnippet` methos allows are only folowing attribute names:\n\n- theme\n- size\n- tabindex\n- callback\n- expired-callback\n- error-callback\n\n> Any different attribute name will be rejected\n\n#### Customization\n\nIn `config/recaptcha.php` you can customize reCAPTCHA widget setting `tag_attributes` array values. Take a look to `tag_attributes` section in [Complete configuration](configuration.md#complete-configuration)\n\n### ReCAPTCHA v2 Invisible\n\n#### htmlScriptTagJsApi(\\$configuration)\n\n`$configuration` argument can have following keys:\n\n- `form_id` set reCAPTCHA form ID. This will override `default_form_id` in `config/recaptcha.php`. This value will be returned by `getFormId()` function in order to set the form tag `id` property.\n\n#### Form set-up\n\nAfter you have to insert `htmlFormButton($button_label, $properties)` helper inside the form where you want to use reCAPTCHA.\n\nThis function creates submit button therefore you don't have to insert `<input type=\"submit\">` or similar.\n\nYou can also use `ReCaptcha::htmlFormButton($button_label, $properties)` .\n\n`$button_label` is what you want to write on the submit button\n\n```html\n<form id=\"{{ getFormId() }}\">\n  @csrf ... {!! htmlFormButton($button_label, $properties) !!}\n</form>\n```\n\n> DO NOT forget `@csrf` blade directive\n\n#### getFormId()\n\n`getFormId` function returns the default form ID value. This is the value of either `default_form_id` in `config/recaptcha.php` or `$configuration['form_id']` previously set as arguments of `htmlScriptTagJsApi` helper.\n\n> `$configuration['form_id']` overrides default settings.\n\n#### htmlFormButton()\n\n`htmlFormButton` function accepts 2 arguments:\n\n- `$button_label`: (string: optional) the button lable. For example: `Subscribe!`;\n- `$properties`: (array: optional) the HTML button properties. For example:\n\n```php\n// $properties =\n[\n    'class' => 'btn btn-info',\n    'data-foo' => 'bar'\n]\n```\n\n> If `data-sitekey` and `data-callback` properties are set, they will be overwritten\n\n> If `class` property is set the value `g-recaptcha` will be appended\n\n## Verify submitted data\n\nAdd `recaptcha` to your rules\n\n```php\n$validator = Validator::make(request()->all(), [\n    ...\n    'g-recaptcha-response' => 'recaptcha',\n    // OR since v4.0.0\n    recaptchaFieldName() => recaptchaRuleName()\n]);\n\n// check if validator fails\nif($validator->fails()) {\n    ...\n    $errors = $validator->errors();\n}\n```\n\n\n## Embed in Blade\n\nInsert `htmlScriptTagJsApi($config)` helper before closing `</head>` tag.\n\n```html\n<!DOCTYPE html>\n<html>\n    <head>\n        ...\n        {!! htmlScriptTagJsApi([\n            'action' => 'homepage',\n            'callback_then' => 'callbackThen',\n            'callback_catch' => 'callbackCatch'\n        ]) !!}\n\n        <!-- OR! -->\n        \n        {!! htmlScriptTagJsApi([\n            'action' => 'homepage',\n            'custom_validation' => 'myCustomValidation'\n        ]) !!}\n    </head>\n```\n`$config` is required and is an associative array containing configuration parameters required for the JavaScript validation handling. \n\nThe keys are:\n\n| Key               | Required  | Description                                                                                                                                                           | Default value |\n|-------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|\n| `action` \t        | no        | is the `action` parameter required by reCAPTCHA v3 API (<a href=\"https://developers.google.com/recaptcha/docs/v3\" target=\"_blank\">further info</a>)  \t                | `homepage`    |\n| `custom_validation`   | no    \t| is the name of your custom callback javascript function who will override the built-in javascript validation system of this package                               | empty string  |\n| `callback_then`   | no    \t| (overlooked if `custom_validation`is set) is the name of your custom callback javascript function called by the built-in javascript validation system of this package in case of response success   \t| empty string  |\n| `callback_catch` \t| no \t    | (overlooked if `custom_validation`is set) is the name of your custom callback javascript function called by the built-in javascript validation system in this package in case of response fault \t    | empty string  |\n\n\n## Built-in javascript validation system\n\nAs callback of `grecaptcha.execute` an ajax call to `config('recaptcha.default_validation_route')` will be performed using `fetch` function. In case of successful response a Promise object will be received and passed as parameter to the `callback_then` function you have set. In not set, no actions will be performed.\n\nSame will happen with `callback_catch`. `callback_catch` will be called in event of response errors and errors will pass as parameter et that function. If not set, no actions will be performed.\n\nPlease, go to <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch\" target=\"_blank\">Using Fetch</a> for further information on `fetch` javascript function.\n\n> **Warning!!! Check browser compatibility** \n`fetch` function has compatibility issues with some browser like IE. Please create a custom validation function and set `custom_validation` with its name. That function has to accept as argument the `token`received from Google reCAPTCHA API.\n>\n> <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Browser_compatibility\" target=\"_blank\">Fetch browser compatibility</a> \n\n\n### Validation Laravel route\n\nDefault validation route is `config('recaptcha.default_validation_route', 'biscolab-recaptcha/validate')`.  \nRoute and relative Controller are built-in in the package. The route if filtered and protected by Laravel `web` Middleware, that's why is important you embed `csrf-token` HTML meta tag and send `X-Requested-Wit` and `X-CSRF-TOKEN` headers.\n\nYou can also change the validation end-point changing `default_validation_route` value in `recaptcha.php` config file.\n\n```html\n<head>\n    ...\n    <!-- IMPORTANT!!! remember CSRF token -->\n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n</head>\n```\n\n### Validation response object\n\nThe output will be a JSON containing following data:\n\n* **Default output without errors**\n```json\n{\n    \"action\":\"homepage\",\n    \"challenge_ts\":\"2019-01-29T00:42:08Z\",\n    \"hostname\":\"www.yourdomain.ext\",\n    \"score\":0.9,\n    \"success\":true\n}\n```\n* **Output when calling IP is included in \"skip_ip\" config whitelist**\n```json\n{\n    \"skip_by_ip\":true,\n    \"score\":0.9,\n    \"success\":true\n}\n```\n> If you embed code in your blade file using `htmlScriptTagJsApiV3` helper no validation call will be performed!\n>\n> More info at <a href=\"#complete-configuration\">Configuration page</a>\n* **Output with an empty response from Google reCAPTCHA API**\n```json\n{\n    \"error\":\"cURL response empty\",\n    \"score\":0.1,\n    \"success\":false\n}\n```\n\nIn the next paragraph you can learn how handle Validation promise object\n\n### \"callback_then\" and \"callback_catch\"\n\nAfter built-in validation you should do something. How? Using `callback_then` and `callback_catch` functions.\n\nWhat you have to do is just create functions and set parameters with their names.\n\n* `callback_then` must receive one argument of type `Promise`.\n\n* `callback_catch` must receive one argument of type `string`\n\nThe result should be something like that:\n\n```html\n<head>\n    ...\n    <!-- IMPORTANT!!! remember CSRF token -->\n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n    ...\n    <script type=\"text/javascript\">\n        function callbackThen(response){\n        \t// read HTTP status\n            console.log(response.status);\n            \n            // read Promise object\n            response.json().then(function(data){\n                console.log(data);\n            });\n        }\n        function callbackCatch(error){\n            console.error('Error:', error)\n        }   \n    </script>    \n    ...\n    {!! htmlScriptTagJsApiV3([\n        'action' => 'homepage',\n        'callback_then' => 'callbackThen',\n        'callback_catch' => 'callbackCatch'\n    ]) !!}    \n</head>\n``` \n\n### \"custom_validation\" function\n\nAs just said you can handle validation with your own function. To do that you have to write your function and set `custom_validation` parameter with its name.\n\nThe result should be something like that:\n\n```html\n<head>\n    ...\n    <!-- IMPORTANT!!! remember CSRF token --> \n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n    ...\n    <script type=\"text/javascript\">\n        function myCustomValidation(token) {\n            // do something with token \n        }\n    </script>    \n    ...\n    {!! htmlScriptTagJsApiV3([\n        'action' => 'homepage',\n        'custom_validation' => 'myCustomValidation'\n    ]) !!}    \n</head>\n``` \n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"biscolab/laravel-recaptcha\",\n    \"description\": \"Simple and painless Google reCAPTCHA package for Laravel framework\",\n    \"license\": \"MIT\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"recaptcha\",\n        \"captcha\",\n        \"laravel\",\n        \"validation\"\n    ],\n    \"homepage\": \"https://biscolab.com/laravel-recaptcha\",\n    \"authors\": [\n        {\n            \"name\": \"Roberto Belotti\",\n            \"email\": \"roby.belotti@gmail.com\",\n            \"homepage\": \"https://biscolab.com\",\n            \"role\": \"Developer\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"illuminate/routing\": \"^7.0|^8.0|^9.0|^10.0|^11.0\",\n        \"illuminate/support\": \"^7.0|^8.0|^9.0|^10.0|^11.0\"\n    },\n    \"require-dev\": {\n        \"orchestra/testbench\": \"5.*|6.*|^7.0|^8.0|^9.0\",\n        \"phpunit/phpunit\": \"^9.1|^10.5\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Biscolab\\\\ReCaptcha\\\\\": \"src/\"\n        },\n        \"files\": [\n            \"src/helpers.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Biscolab\\\\ReCaptcha\\\\Tests\\\\\": \"tests/\"\n        }\n    },\n    \"scripts\": {\n        \"test\": \"vendor/bin/phpunit --colors=always\"\n    },\n    \"suggest\": {\n        \"biscolab/laravel-authlog\": \"It allows to handle logged-in users and force log-out if needed\"\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"Biscolab\\\\ReCaptcha\\\\ReCaptchaServiceProvider\"\n            ],\n            \"aliases\": {\n                \"ReCaptcha\": \"Biscolab\\\\ReCaptcha\\\\Facades\\\\ReCaptcha\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "config/recaptcha.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - recaptcha.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\n/**\n * To configure correctly please visit https://developers.google.com/recaptcha/docs/start\n */\nreturn [\n\n    /**\n     *\n     * The site key\n     * get site key @ www.google.com/recaptcha/admin\n     *\n     */\n    'api_site_key'                 => env('RECAPTCHA_SITE_KEY', ''),\n\n    /**\n     *\n     * The secret key\n     * get secret key @ www.google.com/recaptcha/admin\n     *\n     */\n    'api_secret_key'               => env('RECAPTCHA_SECRET_KEY', ''),\n\n    /**\n     *\n     * ReCATCHA version\n     * Supported: \"v2\", \"invisible\", \"v3\",\n     *\n     * get more info @ https://developers.google.com/recaptcha/docs/versions\n     *\n     */\n    'version'                      => 'v2',\n\n    /**\n     *\n     * The curl timout in seconds to validate a recaptcha token\n     * @since v3.5.0\n     *\n     */\n    'curl_timeout'                 => 10,\n\n    /**\n     *\n     * IP addresses for which validation will be skipped\n     * IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed\n     *\n     */\n    'skip_ip'                      => env('RECAPTCHA_SKIP_IP', []),\n\n    /**\n     *\n     * Default route called to check the Google reCAPTCHA token\n     * @since v3.2.0\n     *\n     */\n    'default_validation_route'     => 'biscolab-recaptcha/validate',\n\n    /**\n     *\n     * The name of the parameter used to send Google reCAPTCHA token to verify route\n     * @since v3.2.0\n     *\n     */\n    'default_token_parameter_name' => 'token',\n\n    /**\n     *\n     * The default Google reCAPTCHA language code\n     * It has no effect with v3\n     * @see   https://developers.google.com/recaptcha/docs/language\n     * @since v3.6.0\n     *\n     */\n    'default_language'             => null,\n\n    /**\n     *\n     * The default form ID. Only for \"invisible\" reCAPTCHA\n     * @since v4.0.0\n     *\n     */\n    'default_form_id'              => 'biscolab-recaptcha-invisible-form',\n\n    /**\n     *\n     * Deferring the render can be achieved by specifying your onload callback function and adding parameters to the JavaScript resource.\n     * It has no effect with v3 and invisible\n     * @see   https://developers.google.com/recaptcha/docs/display#explicit_render\n     * @since v4.0.0\n     * Supported true, false\n     *\n     */\n    'explicit'                     => false,\n\n    /**\n     *\n     * Set API domain. You can use \"www.recaptcha.net\" in case \"www.google.com\" is not accessible.\n     * (no check will be made on the entered value)\n     * @see   https://developers.google.com/recaptcha/docs/faq#can-i-use-recaptcha-globally\n     * @since v4.3.0\n     * Default 'www.google.com' (ReCaptchaBuilder::DEFAULT_RECAPTCHA_API_DOMAIN)\n     *\n     */\n    'api_domain'                   => 'www.google.com',\n\n    /**\n     *\n     * Set `true` when the error message must be null\n     * @since v5.1.0\n     * Default false\n     *\n     */\n    'empty_message' => false,\n\n    /**\n     *\n     * Set either the error message or the errom message translation key\n     * @since v5.1.0\n     * Default 'validation.recaptcha'\n     *\n     */\n    'error_message_key' => 'validation.recaptcha',\n\n    /**\n     *\n     * g-recaptcha tag attributes and grecaptcha.render parameters (v2 only)\n     * @see   https://developers.google.com/recaptcha/docs/display#render_param\n     * @since v4.0.0\n     */\n    'tag_attributes'               => [\n\n        /**\n         * The color theme of the widget.\n         * Supported \"light\", \"dark\"\n         */\n        'theme'            => 'light',\n\n        /**\n         * The size of the widget.\n         * Supported \"normal\", \"compact\"\n         */\n        'size'             => 'normal',\n\n        /**\n         * The tabindex of the widget and challenge.\n         * If other elements in your page use tabindex, it should be set to make user navigation easier.\n         */\n        'tabindex'         => 0,\n\n        /**\n         * The name of your callback function, executed when the user submits a successful response.\n         * The g-recaptcha-response token is passed to your callback.\n         * DO NOT SET \"biscolabOnloadCallback\"\n         */\n        'callback'         => null,\n\n        /**\n         * The name of your callback function, executed when the reCAPTCHA response expires and the user needs to re-verify.\n         * DO NOT SET \"biscolabOnloadCallback\"\n         */\n        'expired-callback' => null,\n\n        /**\n         * The name of your callback function, executed when reCAPTCHA encounters an error (usually network connectivity) and cannot continue until connectivity is restored.\n         * If you specify a function here, you are responsible for informing the user that they should retry.\n         * DO NOT SET \"biscolabOnloadCallback\"\n         */\n        'error-callback'   => null,\n    ]\n];\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" backupGlobals=\"false\" backupStaticAttributes=\"false\" bootstrap=\"vendor/autoload.php\" colors=\"true\" convertErrorsToExceptions=\"true\" convertNoticesToExceptions=\"true\" convertWarningsToExceptions=\"true\" processIsolation=\"false\" stopOnFailure=\"false\" xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/9.3/phpunit.xsd\">\n  <coverage processUncoveredFiles=\"true\">\n    <include>\n      <directory suffix=\".php\">./src</directory>\n    </include>\n    <exclude>\n      <directory suffix=\".php\">./vendor</directory>\n      <directory suffix=\".php\">./config</directory>\n    </exclude>\n  </coverage>\n  <testsuites>\n    <testsuite name=\"Unit\">\n      <directory>./tests</directory>\n    </testsuite>\n  </testsuites>\n</phpunit>\n"
  },
  {
    "path": "src/Controllers/ReCaptchaController.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaController.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 4/2/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Controllers;\n\nuse Illuminate\\Routing\\Controller;\n\n/**\n * Class ReCaptchaController\n * @package Biscolab\\ReCaptcha\\Controllers\n */\nclass ReCaptchaController extends Controller\n{\n\n\t/**\n\t * @return array\n\t */\n\tpublic function validateV3(): array\n\t{\n\n\t\t$token = request()->input(config('recaptcha.default_token_parameter_name', 'token'), '');\n\n\t\treturn recaptcha()->validate($token);\n\t}\n}"
  },
  {
    "path": "src/Exceptions/InvalidConfigurationException.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - InvalidConfigurationException.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 4/9/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Exceptions;\n\nclass InvalidConfigurationException extends \\Exception\n{\n\n}"
  },
  {
    "path": "src/Facades/ReCaptcha.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptcha.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Facades;\n\nuse Illuminate\\Support\\Facades\\Facade;\n\n/**\n * Class ReCaptcha\n * @package Biscolab\\ReCaptcha\\Facades\n *\n * @method static string htmlScriptTagJsApi(?array $config = [])\n * @method static string htmlFormButton(?string $button_label = '', ?array $properties = [])\n * @method static string htmlFormSnippet()\n * @method static string getFormId()\n */\nclass ReCaptcha extends Facade\n{\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n\n        return 'recaptcha';\n    }\n}\n"
  },
  {
    "path": "src/ReCaptchaBuilder.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaBuilder.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha;\n\nuse Illuminate\\Support\\Arr;\nuse Symfony\\Component\\HttpFoundation\\IpUtils;\n\n/**\n * Class ReCaptchaBuilder\n * @package Biscolab\\ReCaptcha\n */\nclass ReCaptchaBuilder\n{\n\n    /**\n     * @var string\n     */\n    const DEFAULT_API_VERSION = 'v2';\n\n    /**\n     * @var int\n     */\n    const DEFAULT_CURL_TIMEOUT = 10;\n\n    /**\n     * @var string\n     */\n    const DEFAULT_ONLOAD_JS_FUNCTION = 'biscolabOnloadCallback';\n\n    /**\n     * @var string\n     */\n    const DEFAULT_RECAPTCHA_RULE_NAME = 'recaptcha';\n\n    /**\n     * @var string\n     */\n    const DEFAULT_RECAPTCHA_FIELD_NAME = 'g-recaptcha-response';\n\n    /**\n     * @var string\n     */\n    const DEFAULT_RECAPTCHA_API_DOMAIN = 'www.google.com';\n\n    /**\n     * The Site key\n     * please visit https://developers.google.com/recaptcha/docs/start\n     * @var string\n     */\n    protected $api_site_key;\n\n    /**\n     * The Secret key\n     * please visit https://developers.google.com/recaptcha/docs/start\n     * @var string\n     */\n    protected $api_secret_key;\n\n    /**\n     * The chosen ReCAPTCHA version\n     * please visit https://developers.google.com/recaptcha/docs/start\n     * @var string\n     */\n    protected $version;\n\n    /**\n     * Whether is true the ReCAPTCHA is inactive\n     * @var boolean\n     */\n    protected $skip_by_ip = false;\n\n    /**\n     * The API domain (default: retrieved from config file)\n     * @var string\n     */\n    protected $api_domain = '';\n\n    /**\n     * The API request URI\n     * @var string\n     */\n    protected $api_url = '';\n\n    /**\n     * The URI of the API Javascript file to embed in you pages\n     * @var string\n     */\n    protected $api_js_url = '';\n\n    /**\n     * ReCaptchaBuilder constructor.\n     *\n     * @param string      $api_site_key\n     * @param string      $api_secret_key\n     * @param null|string $version\n     */\n    public function __construct(\n        string $api_site_key,\n        string $api_secret_key,\n        ?string $version = self::DEFAULT_API_VERSION\n    ) {\n\n        $this->setApiSiteKey($api_site_key);\n        $this->setApiSecretKey($api_secret_key);\n        $this->setVersion($version);\n        $this->setSkipByIp($this->skipByIp());\n        $this->setApiDomain();\n        $this->setApiUrls();\n    }\n\n    /**\n     * @param string $api_site_key\n     *\n     * @return ReCaptchaBuilder\n     */\n    public function setApiSiteKey(string $api_site_key): ReCaptchaBuilder\n    {\n\n        $this->api_site_key = $api_site_key;\n\n        return $this;\n    }\n\n    /**\n     * @param string $api_secret_key\n     *\n     * @return ReCaptchaBuilder\n     */\n    public function setApiSecretKey(string $api_secret_key): ReCaptchaBuilder\n    {\n\n        $this->api_secret_key = $api_secret_key;\n\n        return $this;\n    }\n\n    /**\n     * @return int\n     */\n    public function getCurlTimeout(): int\n    {\n\n        return config('recaptcha.curl_timeout', self::DEFAULT_CURL_TIMEOUT);\n    }\n\n    /**\n     * @param string $version\n     *\n     * @return ReCaptchaBuilder\n     */\n    public function setVersion(string $version): ReCaptchaBuilder\n    {\n\n        $this->version = $version;\n\n        return $this;\n    }\n\n    /**\n     * @return string\n     */\n    public function getVersion(): string\n    {\n\n        return $this->version;\n    }\n\n    /**\n     * @param bool $skip_by_ip\n     *\n     * @return ReCaptchaBuilder\n     */\n    public function setSkipByIp(bool $skip_by_ip): ReCaptchaBuilder\n    {\n\n        $this->skip_by_ip = $skip_by_ip;\n\n        return $this;\n    }\n\n    /**\n     * @param null|string $api_domain\n     *\n     * @return ReCaptchaBuilder\n     */\n    public function setApiDomain(?string $api_domain = null): ReCaptchaBuilder\n    {\n\n        $this->api_domain = $api_domain ?? config('recaptcha.api_domain', self::DEFAULT_RECAPTCHA_API_DOMAIN);\n\n        return $this;\n    }\n\n    /**\n     * @return string\n     */\n    public function getApiDomain(): string\n    {\n\n        return $this->api_domain;\n    }\n\n    /**\n     * @return ReCaptchaBuilder\n     */\n    public function setApiUrls(): ReCaptchaBuilder\n    {\n\n        $this->api_url = 'https://' . $this->api_domain . '/recaptcha/api/siteverify';\n        $this->api_js_url = 'https://' . $this->api_domain . '/recaptcha/api.js';\n\n        return $this;\n    }\n\n    /**\n     * @return array|mixed\n     */\n    public function getIpWhitelist()\n    {\n\n        $whitelist = config('recaptcha.skip_ip', []);\n\n        if (!is_array($whitelist)) {\n            $whitelist = explode(',', $whitelist);\n        }\n\n        $whitelist = array_map(function ($item) {\n\n            return trim($item);\n        }, $whitelist);\n\n        return $whitelist;\n    }\n\n    /**\n     * Checks whether the user IP address is among IPs \"to be skipped\"\n     *\n     * @return boolean\n     */\n    public function skipByIp(): bool\n    {\n        return IpUtils::checkIp(request()->ip(), $this->getIpWhitelist());\n    }\n\n    /**\n     * Write script HTML tag in you HTML code\n     * Insert before </head> tag\n     *\n     * @param array|null $configuration\n     *\n     * @return string\n     * @throws \\Exception\n     */\n    public function htmlScriptTagJsApi(?array $configuration = []): string\n    {\n\n        $query = [];\n        $html = '';\n\n        // Language: \"hl\" parameter\n        // resources $configuration parameter overrides default language\n        $language = Arr::get($configuration, 'lang');\n        if (!$language) {\n            $language = config('recaptcha.default_language', null);\n        }\n        if ($language) {\n            Arr::set($query, 'hl', $language);\n        }\n\n        // Onload JS callback function: \"onload\" parameter\n        // \"render\" parameter set to \"explicit\"\n        if (config('recaptcha.explicit', null) && $this->version === 'v2') {\n            Arr::set($query, 'render', 'explicit');\n            Arr::set($query, 'onload', self::DEFAULT_ONLOAD_JS_FUNCTION);\n\n            /** @scrutinizer ignore-call */\n            $html = $this->getOnLoadCallback();\n        }\n\n        // Create query string\n        $query = ($query) ? '?' . http_build_query($query) : \"\";\n        $html .= \"<script src=\\\"\" . $this->api_js_url .  $query . \"\\\" async defer></script>\";\n\n        return $html;\n    }\n\n    /**\n     * Call out to reCAPTCHA and process the response\n     *\n     * @param string $response\n     *\n     * @return boolean|array\n     */\n    public function validate($response)\n    {\n\n        if ($this->skip_by_ip) {\n            if ($this->returnArray()) {\n                // Add 'skip_by_ip' field to response\n                return [\n                    'skip_by_ip' => true,\n                    'score'      => 0.9,\n                    'success'    => true\n                ];\n            }\n\n            return true;\n        }\n\n        $params = http_build_query([\n            'secret'   => $this->api_secret_key,\n            'remoteip' => request()->getClientIp(),\n            'response' => $response,\n        ]);\n\n        $url = $this->api_url . '?' . $params;\n\n        if (function_exists('curl_version')) {\n\n            $curl = curl_init($url);\n            curl_setopt($curl, CURLOPT_HEADER, false);\n            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);\n            curl_setopt($curl, CURLOPT_TIMEOUT, $this->getCurlTimeout());\n            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);\n            $curl_response = curl_exec($curl);\n        } else {\n            $curl_response = file_get_contents($url);\n        }\n\n        if (is_null($curl_response) || empty($curl_response)) {\n            if ($this->returnArray()) {\n                // Add 'error' field to response\n                return [\n                    'error'   => 'cURL response empty',\n                    'score'   => 0.1,\n                    'success' => false\n                ];\n            }\n\n            return false;\n        }\n        $response = json_decode(trim($curl_response), true);\n\n        if ($this->returnArray()) {\n            return $response;\n        }\n\n        return $response['success'];\n    }\n\n    /**\n     * @return string\n     */\n    public function getApiSiteKey(): string\n    {\n\n        return $this->api_site_key;\n    }\n\n    /**\n     * @return string\n     */\n    public function getApiSecretKey(): string\n    {\n\n        return $this->api_secret_key;\n    }\n\n    /**\n     * @return bool\n     */\n    protected function returnArray(): bool\n    {\n\n        return ($this->version == 'v3');\n    }\n\n    /**\n     * @return string\n     */\n    public function getOnLoadCallback(): string\n    {\n\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "src/ReCaptchaBuilderInvisible.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaBuilderInvisible.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha;\n\nuse Biscolab\\ReCaptcha\\Exceptions\\InvalidConfigurationException;\nuse Illuminate\\Support\\Arr;\n\n/**\n * Class ReCaptchaBuilderInvisible\n * @package Biscolab\\ReCaptcha\n */\nclass ReCaptchaBuilderInvisible extends ReCaptchaBuilder\n{\n\n    /**\n     * @var null|string\n     */\n    protected $form_id = null;\n\n    /**\n     * ReCaptchaBuilderInvisible constructor.\n     *\n     * @param string $api_site_key\n     * @param string $api_secret_key\n     */\n    public function __construct(string $api_site_key, string $api_secret_key)\n    {\n\n        parent::__construct($api_site_key, $api_secret_key, 'invisible');\n    }\n\n    /**\n     * Write HTML <button> tag in your HTML code\n     * Insert before </form> tag\n     *\n     * @param string     $button_label\n     * @param array|null $properties\n     *\n     * @return string\n     */\n    public function htmlFormButton($button_label = 'Submit', ?array $properties = []): string\n    {\n\n        $tag_properties = '';\n\n        $properties = array_merge([\n            'data-callback' => 'biscolabLaravelReCaptcha',\n        ], $properties, \n        [\n            'data-sitekey'  => $this->api_site_key\n        ]);\n\n        if (empty($properties['class'])) {\n            $properties['class'] = 'g-recaptcha';\n        } else {\n            $properties['class'] .= ' g-recaptcha';\n        }\n\n        ksort($properties);\n\n        if ($properties) {\n//            $tag_properties = str_replace(\"=\", '=\"',\n//                    http_build_query($properties, null, '\" ', PHP_QUERY_RFC3986)) . '\"';\n            $temp_properties = [];\n            foreach ($properties as $k => $v) {\n                $temp_properties[] = $k . '=\"' . $v . '\"';\n            }\n\n            $tag_properties = implode(\" \", $temp_properties);\n        }\n\n        return ($this->version == 'invisible') ? '<button ' . $tag_properties . '>' . $button_label . '</button>' : '';\n    }\n\n    /**\n     * Write script HTML tag in you HTML code\n     * Insert before </head> tag\n     *\n     * @param array|null $configuration\n     *\n     * @return string\n     * @throws \\Exception\n     */\n    public function htmlScriptTagJsApi(?array $configuration = []): string\n    {\n\n        $html = parent::htmlScriptTagJsApi();\n\n        $form_id = Arr::get($configuration, 'form_id');\n        if (!$form_id) {\n            $form_id = $this->getFormId();\n        } else {\n            $this->form_id = $form_id;\n        }\n        $html .= '<script>\n\t\t       function biscolabLaravelReCaptcha(token) {\n\t\t         document.getElementById(\"' . $form_id . '\").submit();\n\t\t       }\n\t\t     </script>';\n\n        return $html;\n    }\n\n    /**\n     * @return string\n     * @throws \\Exception\n     */\n    public function getFormId(): string\n    {\n\n        if (!$this->form_id) {\n            $form_id = config('recaptcha.default_form_id');\n        } else {\n            $form_id = $this->form_id;\n        }\n        if (!$form_id) {\n            throw new InvalidConfigurationException(\"formId required\");\n        }\n\n        return $form_id;\n    }\n}\n\n"
  },
  {
    "path": "src/ReCaptchaBuilderV2.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaBuilderV2.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha;\n\nuse Biscolab\\ReCaptcha\\Exceptions\\InvalidConfigurationException;\nuse Illuminate\\Support\\Arr;\n\n/**\n * Class ReCaptchaBuilderV2\n * @package Biscolab\\ReCaptcha\n */\nclass ReCaptchaBuilderV2 extends ReCaptchaBuilder\n{\n\n    protected static $allowed_data_attribute = [\n        \"theme\",\n        \"size\",\n        \"tabindex\",\n        \"callback\",\n        \"expired-callback\",\n        \"error-callback\",\n    ];\n\n    /**\n     * ReCaptchaBuilderV2 constructor.\n     *\n     * @param string $api_site_key\n     * @param string $api_secret_key\n     */\n    public function __construct(string $api_site_key, string $api_secret_key)\n    {\n\n        parent::__construct($api_site_key, $api_secret_key, 'v2');\n    }\n\n    /**\n     * Write ReCAPTCHA HTML tag in your FORM\n     * Insert before </form> tag\n     * \n     * @param null|array $attributes\n     * @return string\n     */\n    public function htmlFormSnippet(?array $attributes = []): string\n    {\n\n        $data_attributes = [];\n        $config_data_attributes = array_merge($this->getTagAttributes(), self::cleanAttributes($attributes));\n        ksort($config_data_attributes);\n        foreach ($config_data_attributes as $k => $v) {\n            if ($v) {\n                $data_attributes[] = 'data-' . $k . '=\"' . $v . '\"';\n            }\n        }\n\n        $html = '<div class=\"g-recaptcha\" ' . implode(\" \", $data_attributes) . ' id=\"recaptcha-element\"></div>';\n\n        return $html;\n    }\n\n    /**\n     * @return array\n     * @throws InvalidConfigurationException\n     */\n    public function getTagAttributes(): array\n    {\n\n        $tag_attributes = [\n            'sitekey' => $this->api_site_key\n        ];\n\n        $tag_attributes = array_merge($tag_attributes, config('recaptcha.tag_attributes', []));\n\n        if (Arr::get($tag_attributes, 'callback') === ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION) {\n            throw new InvalidConfigurationException('Property \"callback\" (\"data-callback\") must be different from \"' . ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION . '\"');\n        }\n\n        if (Arr::get($tag_attributes, 'expired-callback') === ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION) {\n            throw new InvalidConfigurationException('Property \"expired-callback\" (\"data-expired-callback\") must be different from \"' . ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION . '\"');\n        }\n\n        if (Arr::get($tag_attributes, 'error-callback') === ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION) {\n            throw new InvalidConfigurationException('Property \"error-callback\" (\"data-error-callback\") must be different from \"' . ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION . '\"');\n        }\n\n        return $tag_attributes;\n    }\n\n    /**\n     * @return string\n     */\n    public function getOnLoadCallback(): string\n    {\n\n        $attributes = $this->getTagAttributes();\n\n        return \"<script>var biscolabOnloadCallback = function() {grecaptcha.render('recaptcha-element', \" . json_encode($attributes) . \");};</script>\";\n    }\n\n    /**\n     * Compare given attributes with allowed attributes\n     *\n     * @param array|null $attributes\n     * @return array\n     */\n    public static function cleanAttributes(?array $attributes = []): array\n    {\n        return array_filter($attributes, function ($k) {\n            return in_array($k, self::$allowed_data_attribute);\n        }, ARRAY_FILTER_USE_KEY);\n    }\n}\n"
  },
  {
    "path": "src/ReCaptchaBuilderV3.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaBuilderV3.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 22/1/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha;\n\nuse Illuminate\\Support\\Arr;\n\n/**\n * Class ReCaptchaBuilderV3\n * @package Biscolab\\ReCaptcha\n */\nclass ReCaptchaBuilderV3 extends ReCaptchaBuilder\n{\n\n    /**\n     * ReCaptchaBuilderV3 constructor.\n     *\n     * @param string $api_site_key\n     * @param string $api_secret_key\n     */\n    public function __construct(string $api_site_key, string $api_secret_key)\n    {\n\n        parent::__construct($api_site_key, $api_secret_key, 'v3');\n    }\n\n    public function getTokenParameterName(): string\n    {\n        return config(\n            'recaptcha.default_token_parameter_name',\n            'token'\n        );\n    }\n\n    public function getValidationUrl(): string\n    {\n        return url(config(\n            'recaptcha.default_validation_route',\n            'biscolab-recaptcha/validate'\n        ));\n    }\n\n    public function getValidationUrlWithToken(): string\n    {\n        return implode(\n            \"?\",\n            [\n                $this->getValidationUrl(),\n                $this->getTokenParameterName()\n            ]\n        );\n    }\n\n    /**\n     * Write script HTML tag in you HTML code\n     * Insert before </head> tag\n     *\n     * @param array|null $configuration\n     *\n     * @return string\n     */\n    public function htmlScriptTagJsApi(?array $configuration = []): string\n    {\n\n        if ($this->skip_by_ip) {\n            return '';\n        }\n\n        $html = \"<script src=\\\"\" . $this->api_js_url . \"?render={$this->api_site_key}\\\"></script>\";\n\n        $action = Arr::get($configuration, 'action', 'homepage');\n\n        $js_custom_validation = Arr::get($configuration, 'custom_validation', '');\n\n        // Check if set custom_validation. That function will override default fetch validation function\n        if ($js_custom_validation) {\n\n            $validate_function = ($js_custom_validation) ? \"{$js_custom_validation}(token);\" : '';\n        } else {\n\n            $js_then_callback = Arr::get($configuration, 'callback_then', '');\n            $js_callback_catch = Arr::get($configuration, 'callback_catch', '');\n\n            $js_then_callback = ($js_then_callback) ? \"{$js_then_callback}(response)\" : '';\n            $js_callback_catch = ($js_callback_catch) ? \"{$js_callback_catch}(err)\" : '';\n\n            $validate_function = \"\n                fetch('\" . $this->getValidationUrlWithToken() . \"=' + token, {\n                    headers: {\n                        \\\"X-Requested-With\\\": \\\"XMLHttpRequest\\\",\n                        \\\"X-CSRF-TOKEN\\\": csrfToken.content\n                    }\n                })\n                .then(function(response) {\n                   \t{$js_then_callback}\n                })\n                .catch(function(err) {\n                    {$js_callback_catch}\n                });\";\n        }\n\n        $html .= \"<script>\n                    var csrfToken = document.head.querySelector('meta[name=\\\"csrf-token\\\"]');\n                  grecaptcha.ready(function() {\n                      grecaptcha.execute('{$this->api_site_key}', {action: '{$action}'}).then(function(token) {\n                        {$validate_function}\n                      });\n                  });\n\t\t     </script>\";\n\n        return $html;\n    }\n}\n"
  },
  {
    "path": "src/ReCaptchaServiceProvider.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaServiceProvider.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha;\n\nuse Illuminate\\Support\\Facades\\Route;\nuse Illuminate\\Support\\Facades\\Validator;\nuse Illuminate\\Support\\ServiceProvider;\n\n/**\n * Class ReCaptchaServiceProvider\n * @package Biscolab\\ReCaptcha\n */\nclass ReCaptchaServiceProvider extends ServiceProvider\n{\n\n    /**\n     * Indicates if loading of the provider is deferred.\n     *\n     * @var bool\n     */\n    protected $defer = false;\n\n    /**\n     *\n     */\n    public function boot()\n    {\n\n        $this->addValidationRule();\n        $this->registerRoutes();\n        $this->publishes([\n            __DIR__ . '/../config/recaptcha.php' => config_path('recaptcha.php'),\n        ], 'config');\n    }\n\n    /**\n     * Extends Validator to include a recaptcha type\n     */\n    public function addValidationRule()\n    {\n        $message = null;\n\n        if (!config('recaptcha.empty_message')) {\n            $message = trans(config('recaptcha.error_message_key'));\n        }\n        Validator::extendImplicit(recaptchaRuleName(), function ($attribute, $value) {\n\n            return app('recaptcha')->validate($value);\n        }, $message);\n    }\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n\n        $this->mergeConfigFrom(\n            __DIR__ . '/../config/recaptcha.php',\n            'recaptcha'\n        );\n\n        $this->registerReCaptchaBuilder();\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides(): array\n    {\n\n        return ['recaptcha'];\n    }\n\n    /**\n     * @return ReCaptchaServiceProvider\n     *\n     * @since v3.4.1\n     */\n    protected function registerRoutes(): ReCaptchaServiceProvider\n    {\n\n        Route::get(\n            config('recaptcha.default_validation_route', 'biscolab-recaptcha/validate'),\n            ['uses' => 'Biscolab\\ReCaptcha\\Controllers\\ReCaptchaController@validateV3']\n        )->middleware('web');\n\n        return $this;\n    }\n\n    /**\n     * Register the HTML builder instance.\n     *\n     * @return void\n     */\n    protected function registerReCaptchaBuilder()\n    {\n\n        $this->app->singleton('recaptcha', function ($app) {\n\n            $recaptcha_class = '';\n\n            switch (config('recaptcha.version')) {\n                case 'v3':\n                    $recaptcha_class = ReCaptchaBuilderV3::class;\n                    break;\n                case 'v2':\n                    $recaptcha_class = ReCaptchaBuilderV2::class;\n                    break;\n                case 'invisible':\n                    $recaptcha_class = ReCaptchaBuilderInvisible::class;\n                    break;\n            }\n\n            return new $recaptcha_class(config('recaptcha.api_site_key'), config('recaptcha.api_secret_key'));\n        });\n    }\n}\n"
  },
  {
    "path": "src/helpers.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - helpers.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\n\nif (!function_exists('recaptcha')) {\n    /**\n     * @return Biscolab\\ReCaptcha\\ReCaptchaBuilder|\\Biscolab\\ReCaptcha\\ReCaptchaBuilderV2|\\Biscolab\\ReCaptcha\\ReCaptchaBuilderInvisible|\\Biscolab\\ReCaptcha\\ReCaptchaBuilderV3\n     */\n    function recaptcha(): \\Biscolab\\ReCaptcha\\ReCaptchaBuilder\n    {\n\n        return app('recaptcha');\n    }\n}\n\n/**\n * call ReCaptcha::htmlScriptTagJsApi()\n * Write script HTML tag in you HTML code\n * Insert before </head> tag\n *\n * @param $config ['form_id'] required if you are using invisible ReCaptcha\n */\nif (!function_exists('htmlScriptTagJsApi')) {\n\n    /**\n     * @param array|null $config\n     *\n     * @return string\n     */\n    function htmlScriptTagJsApi(?array $config = []): string\n    {\n\n        return ReCaptcha::htmlScriptTagJsApi($config);\n    }\n}\n\n/**\n * call ReCaptcha::htmlFormButton()\n * Write HTML <button> tag in your HTML code\n * Insert before </form> tag\n *\n * Warning! Using only with ReCAPTCHA INVISIBLE\n *\n * @param $buttonInnerHTML What you want to write on the submit button\n */\nif (!function_exists('htmlFormButton')) {\n\n    /**\n     * @param null|string $button_label\n     * @param array|null  $properties\n     *\n     * @return string\n     */\n    function htmlFormButton(?string $button_label = 'Submit', ?array $properties = []): string\n    {\n\n        return ReCaptcha::htmlFormButton($button_label, $properties);\n    }\n}\n\n/**\n * call ReCaptcha::htmlFormSnippet()\n * Write ReCAPTCHA HTML tag in your FORM\n * Insert before </form> tag\n *\n * Warning! Using only with ReCAPTCHA v2\n */\nif (!function_exists('htmlFormSnippet')) {\n\n    /**\n     * @param null|array $attributes\n     * @return string\n     */\n    function htmlFormSnippet(?array $attributes = []): string\n    {\n\n        return ReCaptcha::htmlFormSnippet($attributes);\n    }\n}\n\n/**\n * call ReCaptcha::getFormId()\n * return the form ID\n * Warning! Using only with ReCAPTCHA invisible\n */\nif (!function_exists('getFormId')) {\n\n    /**\n     * @return string\n     */\n    function getFormId(): string\n    {\n\n        return ReCaptcha::getFormId();\n    }\n}\n\n/**\n * return ReCaptchaBuilder::DEFAULT_RECAPTCHA_RULE_NAME value (\"recaptcha\")\n * Use V2 (checkbox and invisible)\n */\nif (!function_exists('recaptchaRuleName')) {\n\n    /**\n     * @return string\n     */\n    function recaptchaRuleName(): string\n    {\n\n        return \\Biscolab\\ReCaptcha\\ReCaptchaBuilder::DEFAULT_RECAPTCHA_RULE_NAME;\n    }\n}\n\n/**\n * return ReCaptchaBuilder::DEFAULT_RECAPTCHA_FIELD_NAME value \"g-recaptcha-response\"\n * Use V2 (checkbox and invisible)\n */\nif (!function_exists('recaptchaFieldName')) {\n\n    /**\n     * @return string\n     */\n    function recaptchaFieldName(): string\n    {\n\n        return \\Biscolab\\ReCaptcha\\ReCaptchaBuilder::DEFAULT_RECAPTCHA_FIELD_NAME;\n    }\n}\n"
  },
  {
    "path": "tests/ReCaptchaConfigurationTest.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaConfigurationTest.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 13/2/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilder;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV2;\n\n/**\n * Class ReCaptchaConfigurationTest\n * @package Biscolab\\ReCaptcha\\Tests\n */\nclass ReCaptchaConfigurationTest extends TestCase\n{\n\n\t/**\n\t * @var ReCaptchaBuilder\n\t */\n\tprotected $recaptcha;\n\n\t/**\n\t * @test\n\t */\n\tpublic function testGetApiSiteKey() {\n\t\t$this->assertEquals(\"api_site_key\", $this->recaptcha->getApiSiteKey());\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testGetApiSecretKey() {\n\t\t$this->assertEquals(\"api_secret_key\", $this->recaptcha->getApiSecretKey());\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testSkipIpWhiteListIsArray()\n\t{\n\n\t\t$ip_whitelist = $this->recaptcha->getIpWhitelist();\n\t\t$this->assertTrue(is_array($ip_whitelist));\n\t\t$this->assertCount(2, $ip_whitelist);\n\n\t\t$this->assertEquals('10.0.0.1', $ip_whitelist[0]);\n\t\t$this->assertEquals('10.0.0.2', $ip_whitelist[1]);\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testCurlTimeoutIsSet()\n\t{\n\n\t\t$this->assertEquals(3, $this->recaptcha->getCurlTimeout());\n\t}\n\n\t/**\n\t * Define environment setup.\n\t *\n\t * @param  \\Illuminate\\Foundation\\Application $app\n\t *\n\t * @return void\n\t */\n\tprotected function getEnvironmentSetUp($app)\n\t{\n\n\t\t$app['config']->set('recaptcha.api_site_key', 'api_site_key');\n\t\t$app['config']->set('recaptcha.api_secret_key', 'api_secret_key');\n\t\t$app['config']->set('recaptcha.skip_ip', '10.0.0.1,10.0.0.2');\n\t\t$app['config']->set('recaptcha.curl_timeout', 3);\n\t}\n\n\t/**\n\t * Setup the test environment.\n\t */\n\tprotected function setUp(): void\n\t{\n\n\t\tparent::setUp(); // TODO: Change the autogenerated stub\n\n\t\t$this->recaptcha = recaptcha();\n\t}\n}"
  },
  {
    "path": "tests/ReCaptchaCustomApiDomainTest.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaCustomApiDomainTest.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 13/9/2020\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderInvisible;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV2;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV3;\n\nclass ReCaptchaCustomApiDomainTest extends TestCase\n{\n\n    /**\n     * @var ReCaptchaBuilderInvisible\n     */\n    protected $recaptcha_invisible;\n\n    /**\n     * @var ReCaptchaBuilderV2\n     */\n    protected $recaptcha_v2;\n\n    /**\n     * @var ReCaptchaBuilderV3\n     */\n    protected $recaptcha_v3;\n\n    /**\n     * @test\n     */\n    public function testRecaptchaApiDomainChangesByConfig()\n    {\n        $this->app['config']->set('recaptcha.api_domain', 'www.recaptcha.net');\n        $this->assertEquals(\"www.recaptcha.net\", $this->recaptcha_v2->getApiDomain());\n        $this->assertEquals(\"www.recaptcha.net\", $this->recaptcha_invisible->getApiDomain());\n        $this->assertEquals(\"www.recaptcha.net\", $this->recaptcha_v3->getApiDomain());\n    }\n\n    /**\n     * @test\n     */\n    public function testRecaptchaApiDomainChangesByConfigInHtmlScriptTagJsApi()\n    {\n        $this->assertStringContainsString(\"https://www.recaptcha.net/recaptcha/api.js\", $this->recaptcha_v2->htmlScriptTagJsApi());\n        $this->assertStringContainsString(\"https://www.recaptcha.net/recaptcha/api.js\", $this->recaptcha_invisible->htmlScriptTagJsApi());\n        $this->assertStringContainsString(\"https://www.recaptcha.net/recaptcha/api.js\", $this->recaptcha_v3->htmlScriptTagJsApi());\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n\n        $app['config']->set('recaptcha.api_domain', 'www.recaptcha.net');\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp(): void\n    {\n\n        parent::setUp(); // TODO: Change the autogenerated stub\n        $this->recaptcha_invisible = new ReCaptchaBuilderInvisible('api_site_key', 'api_secret_key');\n        $this->recaptcha_v2 = new ReCaptchaBuilderV2('api_site_key', 'api_secret_key');\n        $this->recaptcha_v3 = new ReCaptchaBuilderV3('api_site_key', 'api_secret_key');\n    }\n}\n"
  },
  {
    "path": "tests/ReCaptchaHelpersInvisibleTest.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaHelpersInvisibleTest.phpp\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 8/8/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\n\nclass ReCaptchaHelpersInvisibleTest extends TestCase\n{\n\n    /**\n     * @test\n     */\n    public function testHtmlScriptTagJsApiCalledByFacade()\n    {\n\n        ReCaptcha::shouldReceive('htmlScriptTagJsApi')\n            ->once()\n            ->with([\"form_id\" => \"test-form\"]);\n\n        htmlScriptTagJsApi([\"form_id\" => \"test-form\"]);\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlFormButtonCalledByFacade()\n    {\n\n        ReCaptcha::shouldReceive('htmlFormButton')\n            ->once()\n            ->with(\"Inner text\", ['id' => 'button_id']);\n\n        htmlFormButton(\"Inner text\", ['id' => 'button_id']);\n    }\n\n    /**\n     * @test\n     */\n    public function testGetFormIdCalledByFacade()\n    {\n\n        ReCaptcha::shouldReceive('getFormId')\n            ->once();\n\n        getFormId();\n    }\n\n    public function testHtmlFormButtonConfiguration()\n    {\n        $button_html = htmlFormButton(\"Inner text\", ['id' => 'button_id', 'class' => 'button_class', 'data-sitekey' => 'custom-data-sitekey', 'data-callback' => 'myCallback']);\n\n        $this->assertEquals('<button class=\"button_class g-recaptcha\" data-callback=\"myCallback\" data-sitekey=\"api_site_key\" id=\"button_id\">Inner text</button>', $button_html);\n    }\n\n    /**\n     * @test\n     * @expectedException \\TypeError\n     */\n    public function testHtmlFormSnippetCalledByFacade()\n    {\n\n        $this->expectException('\\TypeError');\n        ReCaptcha::shouldReceive('htmlFormSnippet')\n            ->once();\n\n        htmlFormSnippet();\n    }\n\n    public function testGetFormIdReturnDefaultFormIdValue()\n    {\n        $this->assertEquals('biscolab-recaptcha-invisible-form', getFormId());\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n\n        $app['config']->set('recaptcha.api_site_key', 'api_site_key');\n        $app['config']->set('recaptcha.api_site_key', 'api_site_key');\n        $app['config']->set('recaptcha.version', 'invisible');\n    }\n}\n"
  },
  {
    "path": "tests/ReCaptchaHelpersV2ExplicitTest.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaHelpersV2ExplicitTest.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 2/9/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV2;\n\nclass ReCaptchaHelpersV2ExplicitTest extends TestCase\n{\n\n    /**\n     * @test\n     */\n    public function testGetOnLoadCallbackFunction()\n    {\n\n        $recaptcha = \\recaptcha();\n        /** @scrutinizer ignore-call */\n        $callback = $recaptcha->getOnLoadCallback();\n\n        $this->assertEquals(\n            '<script>var biscolabOnloadCallback = function() {grecaptcha.render(\\'recaptcha-element\\', {\"sitekey\":\"api_site_key\",\"theme\":\"dark\",\"size\":\"compact\",\"tabindex\":\"2\",\"callback\":\"callbackFunction\",\"expired-callback\":\"expiredCallbackFunction\",\"error-callback\":\"errorCallbackFunction\"});};</script>',\n            $callback\n        );\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlScriptTagJsApiHasJavascriptRenderFunction()\n    {\n\n        $html = htmlScriptTagJsApi();\n\n        $this->assertEquals(\n            '<script>var biscolabOnloadCallback = function() {grecaptcha.render(\\'recaptcha-element\\', {\"sitekey\":\"api_site_key\",\"theme\":\"dark\",\"size\":\"compact\",\"tabindex\":\"2\",\"callback\":\"callbackFunction\",\"expired-callback\":\"expiredCallbackFunction\",\"error-callback\":\"errorCallbackFunction\"});};</script><script src=\"https://www.google.com/recaptcha/api.js?render=explicit&onload=biscolabOnloadCallback\" async defer></script>',\n            $html\n        );\n    }\n\n    /**\n     * @test\n     */\n    public function testTagAttributes()\n    {\n\n        $recaptcha = \\recaptcha();\n        /** @scrutinizer ignore-call */\n        $tag_attributes = $recaptcha->getTagAttributes();\n\n        $this->assertArrayHasKey('sitekey', $tag_attributes);\n        $this->assertArrayHasKey('theme', $tag_attributes);\n        $this->assertArrayHasKey('size', $tag_attributes);\n        $this->assertArrayHasKey('tabindex', $tag_attributes);\n        $this->assertArrayHasKey('callback', $tag_attributes);\n        $this->assertArrayHasKey('expired-callback', $tag_attributes);\n        $this->assertArrayHasKey('error-callback', $tag_attributes);\n\n        $this->assertEquals($tag_attributes['sitekey'], 'api_site_key');\n        $this->assertEquals($tag_attributes['theme'], 'dark');\n        $this->assertEquals($tag_attributes['size'], 'compact');\n        $this->assertEquals($tag_attributes['tabindex'], '2');\n        $this->assertEquals($tag_attributes['callback'], 'callbackFunction');\n        $this->assertEquals($tag_attributes['expired-callback'], 'expiredCallbackFunction');\n        $this->assertEquals($tag_attributes['error-callback'], 'errorCallbackFunction');\n    }\n\n    /**\n     * @test\n     */\n    public function testExpectReCaptchaInstanceOfReCaptchaBuilderV2()\n    {\n\n        $this->assertInstanceOf(ReCaptchaBuilderV2::class, \\recaptcha());\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlFormSnippet()\n    {\n\n        /** @scrutinizer ignore-call */\n        $html_snippet = \\recaptcha()->htmlFormSnippet();\n        $this->assertEquals(\n            '<div class=\"g-recaptcha\" data-callback=\"callbackFunction\" data-error-callback=\"errorCallbackFunction\" data-expired-callback=\"expiredCallbackFunction\" data-sitekey=\"api_site_key\" data-size=\"compact\" data-tabindex=\"2\" data-theme=\"dark\" id=\"recaptcha-element\"></div>',\n            $html_snippet\n        );\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n\n        $app['config']->set('recaptcha.api_site_key', 'api_site_key');\n        $app['config']->set('recaptcha.version', 'v2');\n        $app['config']->set('recaptcha.explicit', true);\n        $app['config']->set('recaptcha.tag_attributes', [\n            'theme'            => 'dark',\n            'size'             => 'compact',\n            'tabindex'         => '2',\n            'callback'         => 'callbackFunction',\n            'expired-callback' => 'expiredCallbackFunction',\n            'error-callback'   => 'errorCallbackFunction',\n        ]);\n    }\n}\n"
  },
  {
    "path": "tests/ReCaptchaHelpersV2Test.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaHelpersV2Test.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 8/8/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV2;\n\nclass ReCaptchaHelpersV2Test extends TestCase\n{\n\n    /**\n     * @test\n     */\n    public function testHtmlScriptTagJsApiCalledByFacade()\n    {\n\n        ReCaptcha::shouldReceive('htmlScriptTagJsApi')\n            ->once()\n            ->with([\"key\" => \"val\"]);\n\n        htmlScriptTagJsApi([\"key\" => \"val\"]);\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlFormSnippetCalledByFacade()\n    {\n\n        ReCaptcha::shouldReceive('htmlFormSnippet')\n            ->once();\n\n        htmlFormSnippet();\n    }\n\n    /**\n     * @test\n     */\n    public function testTagAttributes()\n    {\n\n        $recaptcha = \\recaptcha();\n\n        $tag_attributes = $recaptcha->getTagAttributes();\n\n        $this->assertArrayHasKey('sitekey', $recaptcha->getTagAttributes());\n        $this->assertArrayHasKey('theme', $recaptcha->getTagAttributes());\n        $this->assertArrayHasKey('size', $tag_attributes);\n        $this->assertArrayHasKey('tabindex', $tag_attributes);\n        $this->assertArrayHasKey('callback', $tag_attributes);\n        $this->assertArrayHasKey('expired-callback', $tag_attributes);\n        $this->assertArrayHasKey('error-callback', $tag_attributes);\n\n        $this->assertEquals($tag_attributes['sitekey'], 'api_site_key');\n        $this->assertEquals($tag_attributes['theme'], 'dark');\n        $this->assertEquals($tag_attributes['size'], 'compact');\n        $this->assertEquals($tag_attributes['tabindex'], '2');\n        $this->assertEquals($tag_attributes['callback'], 'callbackFunction');\n        $this->assertEquals($tag_attributes['expired-callback'], 'expiredCallbackFunction');\n        $this->assertEquals($tag_attributes['error-callback'], 'errorCallbackFunction');\n    }\n\n    /**\n     * @test\n     */\n    public function testExpectReCaptchaInstanceOfReCaptchaBuilderV2()\n    {\n\n        $this->assertInstanceOf(ReCaptchaBuilderV2::class, \\recaptcha());\n    }\n\n    /**\n     * @expectedException     \\Error\n     */\n    public function testExpectExceptionWhenGetFormIdFunctionIsCalled()\n    {\n        $this->expectException('\\Error');\n        getFormId();\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlFormSnippet()\n    {\n\n        $html_snippet = \\recaptcha()->htmlFormSnippet();\n        $this->assertEquals(\n            '<div class=\"g-recaptcha\" data-callback=\"callbackFunction\" data-error-callback=\"errorCallbackFunction\" data-expired-callback=\"expiredCallbackFunction\" data-sitekey=\"api_site_key\" data-size=\"compact\" data-tabindex=\"2\" data-theme=\"dark\" id=\"recaptcha-element\"></div>',\n            $html_snippet\n        );\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlFormSnippetOverridesDefaultAttributes()\n    {\n\n        $html_snippet = \\recaptcha()->htmlFormSnippet([\n            \"theme\" => \"light\",\n            \"size\" => \"normal\",\n            \"tabindex\" => \"3\",\n            \"callback\" => \"callbackFunctionNew\",\n            \"expired-callback\" => \"expiredCallbackFunctionNew\",\n            \"error-callback\" => \"errorCallbackFunctionNew\",\n            \"not-allowed-attribute\" => \"error\",\n        ]);\n        $this->assertEquals(\n            '<div class=\"g-recaptcha\" data-callback=\"callbackFunctionNew\" data-error-callback=\"errorCallbackFunctionNew\" data-expired-callback=\"expiredCallbackFunctionNew\" data-sitekey=\"api_site_key\" data-size=\"normal\" data-tabindex=\"3\" data-theme=\"light\" id=\"recaptcha-element\"></div>',\n            $html_snippet\n        );\n    }\n\n    /**\n     * @test\n     */\n    public function testCleanAttributesReturnsOnlyAllowedAttributes()\n    {\n        $attributes = ReCaptchaBuilderV2::cleanAttributes([\n            \"theme\" => \"theme\",\n            \"size\" => \"size\",\n            \"tabindex\" => \"tabindex\",\n            \"callback\" => \"callback\",\n            \"expired-callback\" => \"expired-callback\",\n            \"error-callback\" => \"error-callback\",\n            \"not-allowed-attribute\" => \"error\",\n        ]);\n        $this->assertArrayHasKey(\"theme\", $attributes);\n        $this->assertArrayHasKey(\"size\", $attributes);\n        $this->assertArrayHasKey(\"tabindex\", $attributes);\n        $this->assertArrayHasKey(\"callback\", $attributes);\n        $this->assertArrayHasKey(\"expired-callback\", $attributes);\n        $this->assertArrayHasKey(\"error-callback\", $attributes);\n        $this->assertArrayNotHasKey(\"not-allowed-attribute\", $attributes);\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlFormSnippetKeepsDefaultConfigValuesUnlessOtherwiseStated()\n    {\n        $html_snippet = \\recaptcha()->htmlFormSnippet([\n            'callback'         => 'callbackFunction',\n            'expired-callback' => 'expiredCallbackFunction',\n            'error-callback'   => 'errorCallbackFunction',\n        ]);\n        $this->assertEquals(\n            '<div class=\"g-recaptcha\" data-callback=\"callbackFunction\" data-error-callback=\"errorCallbackFunction\" data-expired-callback=\"expiredCallbackFunction\" data-sitekey=\"api_site_key\" data-size=\"compact\" data-tabindex=\"2\" data-theme=\"dark\" id=\"recaptcha-element\"></div>',\n            $html_snippet\n        );\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n\n        $app['config']->set('recaptcha.api_site_key', 'api_site_key');\n        $app['config']->set('recaptcha.version', 'v2');\n        $app['config']->set('recaptcha.tag_attributes', [\n            'theme'            => 'dark',\n            'size'             => 'compact',\n            'tabindex'         => '2',\n            'callback'         => 'callbackFunction',\n            'expired-callback' => 'expiredCallbackFunction',\n            'error-callback'   => 'errorCallbackFunction',\n        ]);\n    }\n}\n"
  },
  {
    "path": "tests/ReCaptchaInvalidConfigurationTest.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaInvalidConfigurationTest.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 4/9/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Exceptions\\InvalidConfigurationException;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilder;\n\n/**\n * Class ReCaptchaInvalidConfigurationTest\n * @package Biscolab\\ReCaptcha\\Tests\n */\nclass ReCaptchaInvalidConfigurationTest extends TestCase\n{\n\n    /**\n     * @test\n     */\n    public function testV2HtmlScriptTagJsApiThrowsInvalidConfigurationException()\n    {\n\n        $this->expectException(InvalidConfigurationException::class);\n\n        htmlScriptTagJsApi();\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n\n        $app['config']->set('recaptcha.api_site_key', 'api_site_key');\n        $app['config']->set('recaptcha.api_secret_key', 'api_secret_key');\n        $app['config']->set('recaptcha.explicit', true);\n        $app['config']->set('recaptcha.tag_attributes.callback', ReCaptchaBuilder::DEFAULT_ONLOAD_JS_FUNCTION);\n    }\n\n}"
  },
  {
    "path": "tests/ReCaptchaLangTest.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaLangTest.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 7/8/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderInvisible;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV2;\n\nclass ReCaptchaLangTest extends TestCase\n{\n\n\t/**\n\t * @var ReCaptchaBuilderInvisible\n\t */\n\tprotected $recaptcha_invisible;\n\n\t/**\n\t * @var ReCaptchaBuilderV2\n\t */\n\tprotected $recaptcha_v2;\n\n\t/**\n\t * @tests\n\t */\n\tpublic function testHtmlScriptTagJsApiGetHtmlScriptWithHlParam()\n\t{\n\n\t\t$r = ReCaptcha::htmlScriptTagJsApi();\n\t\t$this->assertEquals('<script src=\"https://www.google.com/recaptcha/api.js?hl=it\" async defer></script>', $r);\n\t}\n\n\t/**\n\t * @tests\n\t */\n\tpublic function testHtmlScriptTagJsApiGetHtmlScriptOverridingHlParam()\n\t{\n\n\t\t$r = ReCaptcha::htmlScriptTagJsApi(['lang' => 'en']);\n\t\t$this->assertEquals('<script src=\"https://www.google.com/recaptcha/api.js?hl=en\" async defer></script>', $r);\n\t}\n\n\t/**\n\t * Define environment setup.\n\t *\n\t * @param  \\Illuminate\\Foundation\\Application $app\n\t *\n\t * @return void\n\t */\n\tprotected function getEnvironmentSetUp($app)\n\t{\n\n\t\t$app['config']->set('recaptcha.default_language', 'it');\n\t}\n\n\t/**\n\t * Setup the test environment.\n\t */\n\tprotected function setUp(): void\n\t{\n\n\t\tparent::setUp(); // TODO: Change the autogenerated stub\n\n\t\t$this->recaptcha_invisible = new ReCaptchaBuilderInvisible('api_site_key', 'api_secret_key');\n\t\t$this->recaptcha_v2 = new ReCaptchaBuilderV2('api_site_key', 'api_secret_key');\n\n\t}\n}"
  },
  {
    "path": "tests/ReCaptchaTest.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaTest.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilder;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderInvisible;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV2;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV3;\n\n/**\n * Class ReCaptchaTest\n * @package Biscolab\\ReCaptcha\\Tests\n */\nclass ReCaptchaTest extends TestCase\n{\n\n\t/**\n\t * @var ReCaptchaBuilderInvisible\n\t */\n\tprotected $recaptcha_invisible = null;\n\n\t/**\n\t * @var ReCaptchaBuilderV2\n\t */\n\tprotected $recaptcha_v2 = null;\n\n\t/**\n\t * @var ReCaptchaBuilderV3\n\t */\n\tprotected $recaptcha_v3 = null;\n\n\t/**\n\t * @tests\n\t */\n\tpublic function testHtmlScriptTagJsApiGetHtmlScriptTag()\n\t{\n\n\t\t$r = ReCaptcha::htmlScriptTagJsApi();\n\t\t$this->assertEquals('<script src=\"https://www.google.com/recaptcha/api.js\" async defer></script>', $r);\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testReCaptchaInvisibleHtmlFormButtonDefault()\n\t{\n\n\t\t$recaptcha = $this->recaptcha_invisible;\n\t\t$html_button = $recaptcha->htmlFormButton();\n\t\t$this->assertEquals(\n\t\t\t'<button class=\"g-recaptcha\" data-callback=\"biscolabLaravelReCaptcha\" data-sitekey=\"api_site_key\">Submit</button>',\n\t\t\t$html_button\n\t\t);\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testReCaptchaInvisibleHtmlFormButtonCustom()\n\t{\n\n\t\t$recaptcha = $this->recaptcha_invisible;\n\t\t$html_button = $recaptcha->htmlFormButton('Custom Text');\n\t\t$this->assertEquals(\n\t\t\t'<button class=\"g-recaptcha\" data-callback=\"biscolabLaravelReCaptcha\" data-sitekey=\"api_site_key\">Custom Text</button>',\n\t\t\t$html_button\n\t\t);\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testReCaptchaV2HtmlFormSnippet()\n\t{\n\n\t\t$recaptcha = $this->recaptcha_v2;\n\t\t$html_snippet = $recaptcha->htmlFormSnippet();\n\t\t$this->assertEquals('<div class=\"g-recaptcha\" data-sitekey=\"api_site_key\" data-size=\"normal\" data-theme=\"light\" id=\"recaptcha-element\"></div>', $html_snippet);\n\t}\n\n\t/**\n\t * @test\n\t * @expectedException     \\Error\n\t */\n\tpublic function testReCaptchaInvisibleHtmlFormSnippetShouldThrowError()\n\t{\n\t\t$this->expectException('\\Error');\n\t\t$this->recaptcha_invisible->htmlFormSnippet();\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testSkipByIpAndReturnArrayReturnsDefaultArray()\n\t{\n\n\t\t$mock = $this->getMockBuilder(ReCaptchaBuilder::class)\n\t\t\t->setConstructorArgs([\n\t\t\t\t\"api_site_key\",\n\t\t\t\t\"api_secret_key\"\n\t\t\t])\n\t\t\t->setMethods([\n\t\t\t\t'returnArray'\n\t\t\t])\n\t\t\t->getMock();\n\n\t\t$mock->method('returnArray')\n\t\t\t->willReturn(true);\n\n\t\t$this->setSkipByIp($this->recaptcha_v3, true);\n\n\t\t$validate = $this->recaptcha_v3->validate(\"\");\n\n\t\t$this->assertEquals([\n\t\t\t\"skip_by_ip\" => true,\n\t\t\t\"score\"      => 0.9,\n\t\t\t\"success\"    => true\n\t\t], $validate);\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testSkipByIpReturnsValidResponse()\n\t{\n\n\t\t$this->setSkipByIp($this->recaptcha_invisible, true);\n\t\t$validate = $this->recaptcha_invisible->validate(\"\");\n\n\t\t$this->assertTrue($validate);\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testDefaultCurlTimeout()\n\t{\n\n\t\t$this->assertEquals($this->recaptcha_invisible->getCurlTimeout(), ReCaptchaBuilder::DEFAULT_CURL_TIMEOUT);\n\t\t$this->assertEquals($this->recaptcha_v2->getCurlTimeout(), ReCaptchaBuilder::DEFAULT_CURL_TIMEOUT);\n\t\t$this->assertEquals($this->recaptcha_v3->getCurlTimeout(), ReCaptchaBuilder::DEFAULT_CURL_TIMEOUT);\n\t}\n\n\t/**\n\t * @test\n\t * @expectedException     \\Error\n\t */\n\tpublic function testReCaptchaV2htmlFormButtonShouldThrowError()\n\t{\n\t\t$this->expectException('\\Error');\n\t\t$this->recaptcha_v2->htmlFormButton();\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testRecaptchaFieldNameHelperReturnsReCaptchaBuilderDefaultFieldName()\n\t{\n\t\t$this->assertEquals(ReCaptchaBuilder::DEFAULT_RECAPTCHA_FIELD_NAME, recaptchaFieldName());\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testRecaptchaRuleNameHelperReturnsReCaptchaBuilderDefaultRuleName()\n\t{\n\t\t$this->assertEquals(ReCaptchaBuilder::DEFAULT_RECAPTCHA_RULE_NAME, recaptchaRuleName());\n\t}\n\n\t/**\n\t * @test\n\t */\n\tpublic function testDefaultRecaptchaApiDomainIsGoogleDotCom()\n\t{\n\t\t$this->assertEquals(\"www.google.com\", $this->recaptcha_v2->getApiDomain());\n\t\t$this->assertEquals(\"www.google.com\", $this->recaptcha_invisible->getApiDomain());\n\t\t$this->assertEquals(\"www.google.com\", $this->recaptcha_v3->getApiDomain());\n\t}\n\n\tprotected function setSkipByIp(ReCaptchaBuilder $builder, bool $value)\n\t{\n\n\t\t$reflection = new \\ReflectionClass($builder);\n\t\t$reflection_property = $reflection->getProperty('skip_by_ip');\n\t\t$reflection_property->setAccessible(true);\n\t\t$reflection_property->setValue($builder, $value);\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tprotected function setUp(): void\n\t{\n\n\t\tparent::setUp(); // TODO: Change the autogenerated stub\n\n\t\t$this->recaptcha_invisible = new ReCaptchaBuilderInvisible('api_site_key', 'api_secret_key');\n\t\t$this->recaptcha_v2 = new ReCaptchaBuilderV2('api_site_key', 'api_secret_key');\n\t\t$this->recaptcha_v3 = new ReCaptchaBuilderV3('api_site_key', 'api_secret_key');\n\t}\n}\n"
  },
  {
    "path": "tests/ReCaptchaV3Test.php",
    "content": "<?php\n\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - ReCaptchaV3Test.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 22/1/2019\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Controllers\\ReCaptchaController;\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\nuse Biscolab\\ReCaptcha\\ReCaptchaBuilderV3;\nuse Illuminate\\Support\\Facades\\App;\n\n/**\n * Class ReCaptchaV3Test\n * @package Biscolab\\ReCaptcha\\Tests\n */\nclass ReCaptchaV3Test extends TestCase\n{\n\n    protected $recaptcha_v3 = null;\n\n    /**\n     * @test\n     */\n    public function testGetApiVersion()\n    {\n\n        $this->assertEquals($this->recaptcha_v3->getVersion(), 'v3');\n    }\n\n    /**\n     * @test\n     */\n    public function testAction()\n    {\n\n        $r = $this->recaptcha_v3->htmlScriptTagJsApi(['action' => 'someAction']);\n        $this->assertMatchesRegularExpression('/someAction/', $r);\n    }\n\n    /**\n     * @test\n     */\n    public function testFetchCallbackFunction()\n    {\n\n        $r = $this->recaptcha_v3->htmlScriptTagJsApi(['callback_then' => 'functionCallbackThen']);\n        $this->assertMatchesRegularExpression('/functionCallbackThen\\(response\\)/', $r);\n    }\n\n    /**\n     * @test\n     */\n    public function testcCatchCallbackFunction()\n    {\n\n        $r = $this->recaptcha_v3->htmlScriptTagJsApi(['callback_catch' => 'functionCallbackCatch']);\n        $this->assertMatchesRegularExpression('/functionCallbackCatch\\(err\\)/', $r);\n    }\n\n    /**\n     * @test\n     */\n    public function testCustomValidationFunction()\n    {\n\n        $r = $this->recaptcha_v3->htmlScriptTagJsApi(['custom_validation' => 'functionCustomValidation']);\n        $this->assertMatchesRegularExpression('/functionCustomValidation\\(token\\)/', $r);\n    }\n\n    /**\n     * @test\n     */\n    public function testCustomValidationUrl()\n    {\n\n        $r = $this->recaptcha_v3->htmlScriptTagJsApi();\n        $this->assertMatchesRegularExpression('/http:\\/\\/localhost\\/my-custom-url\\?my-custom-token-name/', $r);\n    }\n\n    /**\n     * @test\n     */\n    public function testValidateController()\n    {\n\n        $controller = App::make(ReCaptchaController::class);\n        $return = $controller->validateV3();\n\n        $this->assertArrayHasKey(\"success\", $return);\n        $this->assertArrayHasKey(\"error-codes\", $return);\n    }\n\n    /**\n     * @test\n     */\n    public function testCurlTimeoutIsSet()\n    {\n\n        $this->assertEquals($this->recaptcha_v3->getCurlTimeout(), 3);\n    }\n\n    /**\n     * @test\n     */\n    public function testHtmlScriptTagJsApiCalledByFacade()\n    {\n\n        ReCaptcha::shouldReceive('htmlScriptTagJsApi')\n            ->once()\n            ->with([]);\n\n        htmlScriptTagJsApi([]);\n    }\n\n    /**\n     * @test\n     */\n    public function testValidationUrlShouldBeMyCustomUrl()\n    {\n        $this->assertEquals($this->recaptcha_v3->getValidationUrl(), \"http://localhost/my-custom-url\");\n    }\n\n    /**\n     * @test\n     */\n    public function testTokenParamNameShouldBeMyCustomTokenParamName()\n    {\n        $this->assertEquals($this->recaptcha_v3->getTokenParameterName(), \"my-custom-token-name\");\n    }\n\n    /**\n     * @test\n     */\n    public function testValidationUrlShouldBeMyCustomValidationUrl()\n    {\n        $this->assertEquals($this->recaptcha_v3->getValidationUrlWithToken(), \"http://localhost/my-custom-url?my-custom-token-name\");\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n\n        $app['config']->set('recaptcha.version', 'v3');\n        $app['config']->set('recaptcha.curl_timeout', 3);\n\n        $app['config']->set('recaptcha.default_validation_route', \"my-custom-url\");\n        $app['config']->set('recaptcha.default_token_parameter_name', \"my-custom-token-name\");\n    }\n\n    /**\n     * Setup the test environment.\n     */\n    protected function setUp(): void\n    {\n\n        parent::setUp(); // TODO: Change the autogenerated stub\n        $this->recaptcha_v3 = new ReCaptchaBuilderV3('api_site_key', 'api_secret_key');\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n/**\n * Copyright (c) 2017 - present\n * LaravelGoogleRecaptcha - TestCase.php\n * author: Roberto Belotti - roby.belotti@gmail.com\n * web : robertobelotti.com, github.com/biscolab\n * Initial version created on: 12/9/2018\n * MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE\n */\n\nnamespace Biscolab\\ReCaptcha\\Tests;\n\nuse Biscolab\\ReCaptcha\\Facades\\ReCaptcha;\nuse Biscolab\\ReCaptcha\\ReCaptchaServiceProvider;\nuse Orchestra\\Testbench\\TestCase as OrchestraTestCase;\n\n/**\n * Class TestCase\n * @package Biscolab\\ReCaptcha\\Tests\n */\nclass TestCase extends OrchestraTestCase\n{\n\n\t/**\n\t * Load package alias\n\t *\n\t * @param  \\Illuminate\\Foundation\\Application $app\n\t *\n\t * @return array\n\t */\n\tprotected function getPackageAliases($app)\n\t{\n\n\t\treturn [\n\t\t\t'ReCaptcha' => ReCaptcha::class,\n\t\t];\n\t}\n\n\t/**\n\t * Load package service provider\n\t *\n\t * @param \\Illuminate\\Foundation\\Application $app\n\t *\n\t * @return array\n\t */\n\tprotected function getPackageProviders($app)\n\t{\n\n\t\treturn [ReCaptchaServiceProvider::class];\n\t}\n}\n"
  }
]