Skip to content
This repository has been archived by the owner on Feb 17, 2022. It is now read-only.

Commit

Permalink
Merge pull request #37 from DarkGhostHunter/master
Browse files Browse the repository at this point in the history
Laravel Octane + Rewrite
  • Loading branch information
DarkGhostHunter authored Apr 9, 2021
2 parents 512c3be + f051197 commit 7b4532d
Show file tree
Hide file tree
Showing 25 changed files with 1,280 additions and 1,245 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,20 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [8.0]
laravel: [8.*]
php: [7.4, 8.0]
laravel: [7.*, 8.*]
dependency-version: [prefer-lowest, prefer-stable]
include:
- laravel: 7.*
testbench: ^5.18
- laravel: 8.*
testbench: ^6.14

name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }}

steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand All @@ -32,7 +34,7 @@ jobs:
coverage: xdebug

- name: Cache dependencies
uses: actions/cache@v1
uses: actions/cache@v2
with:
path: ~/.composer/cache/files
key: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
Expand All @@ -52,5 +54,5 @@ jobs:
COVERALLS_SERVICE_NAME: github
run: |
rm -rf composer.* vendor/
composer require cedx/coveralls
vendor/bin/coveralls build/logs/clover.xml
composer require php-coveralls/php-coveralls
vendor/bin/php-coveralls
193 changes: 105 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![Franck V. - Unsplash (UL) #JjGXjESMxOY](https://images.unsplash.com/photo-1535378620166-273708d44e4c?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1280&h=400&q=80)

[![Latest Version on Packagist](https://img.shields.io/packagist/v/darkghosthunter/captchavel.svg?style=flat-square)](https://packagist.org/packages/darkghosthunter/captchavel) [![License](https://poser.pugx.org/darkghosthunter/captchavel/license)](https://packagist.org/packages/darkghosthunter/larapoke) ![](https://img.shields.io/packagist/php-v/darkghosthunter/captchavel.svg) ![](https://github.com/DarkGhostHunter/Captchavel/workflows/PHP%20Composer/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/Captchavel/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/Captchavel?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/9571f57106069b5f3aac/maintainability)](https://codeclimate.com/github/DarkGhostHunter/Captchavel/maintainability) [![Laravel Octane Incompatible](https://img.shields.io/badge/Laravel%20Octane-Incompatible-red?style=flat&logo=laravel)](https://github.com/laravel/octane)
[![Latest Version on Packagist](https://img.shields.io/packagist/v/darkghosthunter/captchavel.svg?style=flat-square)](https://packagist.org/packages/darkghosthunter/captchavel) [![License](https://poser.pugx.org/darkghosthunter/captchavel/license)](https://packagist.org/packages/darkghosthunter/larapoke) ![](https://img.shields.io/packagist/php-v/darkghosthunter/captchavel.svg) ![](https://github.com/DarkGhostHunter/Captchavel/workflows/PHP%20Composer/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/Captchavel/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/Captchavel?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/9571f57106069b5f3aac/maintainability)](https://codeclimate.com/github/DarkGhostHunter/Captchavel/maintainability) [![Laravel Octane Compatible](https://img.shields.io/badge/Laravel%20Octane-Compatible-success?style=flat&logo=laravel)](https://github.com/laravel/octane)

# Captchavel

Expand All @@ -14,8 +14,6 @@ It uses your Laravel HTTP Client and **HTTP/2**, making your app **fast**. You o
* [Installation](#installation)
* [Set Up](#set-up)
* [Usage](#usage)
- [Checkbox, Invisible and Android challenges](#checkbox-invisible-and-android-challenges)
- [Score driven interaction](#score-driven-interaction)
* [Frontend integration](#frontend-integration)
* [Advanced configuration](#advanced-configuration)
* [Testing with Captchavel](#testing-with-captchavel)
Expand All @@ -24,8 +22,8 @@ It uses your Laravel HTTP Client and **HTTP/2**, making your app **fast**. You o

## Requirements

* Laravel 8.x
* PHP 8.0
* Laravel 7.x, 8.x, or later
* PHP 7.4, 8.0 or later

> If you need support for old versions, consider sponsoring or donating.
Expand All @@ -39,22 +37,22 @@ composer require darkghosthunter/captchavel

## Set up

Add the reCAPTCHA keys for your site to the environment file of your project. You can add each of them for reCAPTCHA v2 **checkbox**, **invisible**, **Android**, and **v3** (score).
Add the reCAPTCHA keys for your site to the environment file of your project. You can add each of them for reCAPTCHA v2 **checkbox**, **invisible**, **Android**, and **score**.

If you don't have one, generate it in your [reCAPTCHA Admin panel](https://www.google.com/recaptcha/admin/).

```dotenv
RECAPTCHA_V2_CHECKBOX_SECRET=6t5geA1UAAAAAN...
RECAPTCHA_V2_CHECKBOX_KEY=6t5geA1UAAAAAN...
RECAPTCHA_CHECKBOX_SECRET=6t5geA1UAAAAAN...
RECAPTCHA_CHECKBOX_KEY=6t5geA1UAAAAAN...
RECAPTCHA_V2_INVISIBLE_SECRET=6t5geA2UAAAAAN...
RECAPTCHA_V2_INVISIBLE_KEY=6t5geA2UAAAAAN...
RECAPTCHA_INVISIBLE_SECRET=6t5geA2UAAAAAN...
RECAPTCHA_INVISIBLE_KEY=6t5geA2UAAAAAN...
RECAPTCHA_V2_ANDROID_SECRET=6t5geA3UAAAAAN...
RECAPTCHA_V2_ANDROID_KEY=6t5geA3UAAAAAN...
RECAPTCHA_ANDROID_SECRET=6t5geA3UAAAAAN...
RECAPTCHA_ANDROID_KEY=6t5geA3UAAAAAN...
RECAPTCHA_V3_SECRET=6t5geA4UAAAAAN...
RECAPTCHA_V3_KEY=6t5geA4UAAAAAN...
RECAPTCHA_SCORE_SECRET=6t5geA4UAAAAAN...
RECAPTCHA_SCORE_KEY=6t5geA4UAAAAAN...
```

This allows you to check different reCAPTCHA mechanisms using the same application, in different environments.
Expand All @@ -63,37 +61,38 @@ This allows you to check different reCAPTCHA mechanisms using the same applicati
## Usage

After you integrate reCAPTCHA into your frontend or Android app, set the Captchavel middleware in the routes you want:
Usage differs based on if you're using checkbox, invisible, or Android challenges, or the v3 score-driven challenge.

* `recaptcha.v2` for Checkbox, Invisible and Android challenges.
* `recaptcha.v3` for Score driven interaction.
### Checkbox, invisible and Android challenges

### Checkbox, Invisible and Android challenges
After you integrate reCAPTCHA into your frontend or Android app, set the Captchavel middleware in the `POST` routes where a form with reCAPTCHA is submitted. The middleware will catch the `g-recaptcha-response` input and check if it's valid.

Add the `recaptcha.v2` middleware to your `POST` routes. The middleware will catch the `g-recaptcha-response` input and check if it's valid.

* `recaptcha.v2:checkbox` for explicitly rendered checkbox challenges.
* `recaptcha.v2:invisible` for invisible challenges.
* `recaptcha.v2:android` for Android app challenges.
* `recaptcha:checkbox` for explicitly rendered checkbox challenges.
* `recaptcha:invisible` for invisible challenges.
* `recaptcha:android` for Android app challenges.

When the validation fails, the user will be redirected back to the form route, or a JSON response will be returned with the validation errors.

```php
Route::post('login', 'LoginController@login')
->middleware('recaptcha.v2:checkbox');
use App\Http\Controllers\Auth\LoginController;

Route::post('login', [LoginController::class, 'login'])->middleware('recaptcha:checkbox');
```

> You can change the input name from `g-recaptcha-response` to a custom using a second parameter, like `recaptcha.v2:checkbox,_recaptcha`.
> You can change the input name from `g-recaptcha-response` to a custom using a second parameter, like `recaptcha.checkbox:my_input_name`.
### Score-driven challenge

### Score driven interaction
The reCAPTCHA v3 middleware works differently from v2. This is a score-driven response is _always_ a success, but the challenge is scored between `0.0` and `1.0`. Robots will get lower scores, while human-like interaction will be higher.

The reCAPTCHA v3 middleware works differently from v2. This is a score-driven challenge between `0.0` and `1.0` where robots will get lower scores than humans. The default threshold is `0.5`.
The default threshold is `0.5`, which will set apart robots that score less than that.

Simply add the `recaptcha.v3` middleware to your route:
Simply add the `recaptcha.score` middleware to your route:

```php
Route::post('comment', 'CommentController@store')
->middleware('recaptcha.v3');
use App\Http\Controllers\CommentController;

Route::post('comment', [CommentController::class, 'create'])->middleware('recaptcha.score');
```

Once the challenge has been received, you will have access to two methods from the Request instance: `isHuman()` and `isRobot()`, which return `true` or `false`:
Expand All @@ -107,7 +106,7 @@ public function store(Request $request, Post $post)

$comment = $post->comment()->make($request->only('body'));

// Flag the comment as "moderated" if it was a written by robot.
// Flag the comment as "moderated" if it was a written by robot.
$comment->moderated = $request->isRobot();

$comment->save();
Expand All @@ -118,36 +117,38 @@ public function store(Request $request, Post $post)

#### Threshold, action and input name

The middleware accepts three parameters in the following order:
The middleware accepts three additional parameters in the following order:

1. Threshold: Values **above or equal** are considered human.
2. Action: The action name to optionally check against.
3. Input: The name of the reCAPTCHA input to verify.

```php
Route::post('comment', 'CommentController@store')
->middleware('recaptcha.v3:0.7,login,custom-recaptcha-input');
use App\Http\Controllers\CommentController;

Route::post('comment', [CommentController::class, 'create'])
->middleware('recaptcha.score:0.7,login,custom-recaptcha-input');
```

> When checking the action name, ensure your Frontend action matches
> When checking the action name, ensure your Frontend action matches .
#### Faking robot and human scores
#### Faking reCAPTCHA scores

You can easily fake a reCAPTCHA v3 response in your local development by setting `CAPTCHAVEL_FAKE` to `true`.
You can easily fake a reCAPTCHA response scores in your local development by setting `CAPTCHAVEL_FAKE` to `true`.

```dotenv
CAPTCHAVEL_FAKE=true
```

Then, you can fake a low-score response by adding an `is_robot` a checkbox, respectively.
This environment variable changes the reCAPTCHA Factory for a fake one, which will fake successful responses from reCAPTCHA, instead of resolving real challenges.

From there, you can fake a robot or human response by adding an `is_robot` and returning `true` or `false`, respectively.

```blade
<form id='login' method="POST">
<input type="email" name="email">
<input type="password" name="password">
<input type="checkbox" name="is_robot" checked>
<button class="g-recaptcha" data-sitekey="{{ captchavel('invisible') }}" data-callback='onSubmit'>Login</button>
<br/>
<form id="comment" method="post">
<textarea name="body"></textarea>
<input type="checkbox" name="is_robot" checked>
<button class="g-recaptcha" data-sitekey="{{ captchavel('invisible') }}" data-callback='onSubmit'>Login</button>
</form>
```

Expand All @@ -174,7 +175,7 @@ You can use the `captchavel()` helper to output the site key depending on the ch
Captchavel is intended to work out-of-the-box, but you can publish the configuration file for fine-tuning and additional reCAPTCHA verification.

```bash
php artisan vendor:publish --provider="DarkGhostHunter\Captchavel\CaptchavelServiceProvider"
php artisan vendor:publish --provider="DarkGhostHunter\Captchavel\CaptchavelServiceProvider" --tag="config"
```

You will get a config file with this array:
Expand All @@ -196,21 +197,31 @@ return [

### Enable Switch

```php
<?php

return [
'enable' => env('CAPTCHAVEL_ENABLE', false),
];
```

By default, Captchavel is disabled, so it doesn't check reCAPTCHA challenges. You can forcefully enable it with the `CAPTCHAVEL_ENABLE` environment variable.

```dotenv
CAPTCHAVEL_ENABLE=true
```

The main switch to enable or disable Captchavel middleware. This can be handy to enable on some local environments to check real interaction using the included localhost test keys.
This can be handy to enable on some local or development environments to check real interaction using the included localhost test keys, which only work on `localhost`.

When switched off, the `g-recaptcha-response` won't be validated in the Request input, so you can safely disregard any frontend script or reCAPTCHA tokens or boxes.
> When switched off, the reCAPTCHA challenge is not validated in the Request input, so you can safely disregard any frontend script or reCAPTCHA tokens or boxes.
### Fake responses

```dotenv
CAPTCHAVEL_FAKE=true
```

Setting this to true will allow your application to [fake v3-score responses from reCAPTCHA servers](#faking-robot-and-human-scores).
If Captchavel is [enabled](#enable-switch), setting this to true will allow your application to [fake v3-score responses from reCAPTCHA servers](#faking-recaptcha-scores).

> This is automatically set to `true` when [running unit tests](#testing-with-captchavel).
Expand Down Expand Up @@ -249,13 +260,39 @@ return [

Here is the full array of [reCAPTCHA credentials](#set-up) to use depending on the version. Do not change the array unless you know what you're doing.

## Testing with Captchavel
## Testing Score with Captchavel

When unit testing your application, this package [automatically fakes reCAPTCHA responses](#fake-responses).
On testing, when Captchavel is disabled, routes set with the v2 middleware won't need to input the challenge in their body as it will be not verified.

> When mocking requests, there is no need to add any reCAPTCHA token or secrets in your tests.
On the other hand, reCAPTCHA v3 (score) responses can be [automatically faked](#fake-responses).

When using reCAPTCHA v3 (score), you can fake a response made by a human or robot by simply using the `fakeHuman()` and `fakeRobot()` methods, which will score `1.0` or `0.0` respectively.
To do that, you should [enable Captchavel](#enable-switch) on your tests, through the `.env.testing` environment file, or in [PHPUnit environment section](https://phpunit.readthedocs.io/en/9.5/configuration.html?highlight=environment#the-env-element). If you use another testing framework, refer to its documentation.

```xml
<phpunit>
<!-- ... -->
<php>
<env name="CAPTCHAVEL_ENABLE" value="true"/>
<env name="CAPTCHAVEL_FAKE" value="true"/>
</php>
</phpunit>
```

Alternatively, you can change the configuration before your unit test:

```php
public function test_this_route()
{
config()->set('captchavel.enable', true);
config()->set('captchavel.fake', true);

// ...
}
```

> When faking challenges, there is no need to add any reCAPTCHA token or secrets in your tests.
When using reCAPTCHA v3 (score), you can fake a response made by a human or robot by simply using the `fakeHuman()` and `fakeRobot()` methods, which will score `1.0` or `0.0` respectively for all subsequent requests.

```php
<?php
Expand All @@ -279,50 +316,30 @@ $this->post('login', [
])->assertViewIs('login.2fa');
```

Alternatively, `fakeScore()` method that will fake any score you set.

> Fake responses don't come with actions, hostnames or APK package names.
### Events

When a reCAPTCHA challenge is resolved, whatever result is received, the `ReCaptchaResponseReceived` event fires with the HTTP Request instance and the reCAPTCHA response.
### Faking Scores manually

### Using your own reCAPTCHA middleware

You may want to create your own reCAPTCHA middleware. Instead of doing one from scratch, you can extend the `BaseReCaptchaMiddleware`.
Alternatively, `fakeScore()` method will fake responses with any score you set.

```php
<?php

namespace App\Http\Middleware;
use DarkGhostHunter\Captchavel\Facades\Captchavel;

use Closure;
use DarkGhostHunter\Captchavel\Http\Middleware\BaseReCaptchaMiddleware;
// A human comment should be public.
Captchavel::fakeScore(0.7);

class MyReCaptchaMiddleware extends BaseReCaptchaMiddleware
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$input = 'g-recaptcha-response';

$this->validateRequest($request, $input);

$response = $this->retrieve($request, $input, 2, 'checkbox');

if ($response->isInvalid()) {
throw $this->validationException($input, 'Complete the reCAPTCHA challenge');
}

return $next($request);
}
}
$this->post('comment', [
'body' => 'This comment was made by a human',
])->assertSee('Your comment has been posted!');

// A robot should have its comment moderated.
Captchavel::fakeScore(0.4);

$this->post('comment', [
'body' => 'Comment made by robot.',
])->assertSee('Your comment will be reviewed before publishing.');
```

## Security
Expand Down
Loading

0 comments on commit 7b4532d

Please sign in to comment.