Skip to content

Instantly share code, notes, and snippets.

@nathanbarrett
Created February 17, 2019 17:35
Show Gist options
  • Save nathanbarrett/1454fc185fcc18c730ea1596b32e2227 to your computer and use it in GitHub Desktop.
Save nathanbarrett/1454fc185fcc18c730ea1596b32e2227 to your computer and use it in GitHub Desktop.
Laravel rule for implementing Google's recaptcha V3
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
class GoogleRecaptchaToken implements Rule
{
/**
* The minimum score that will allow a token to pass
* @var float
*/
protected $minScore = 0.7;
/**
* The client IP address
* @var string
*/
protected $clientIp;
/**
* Create a new rule instance.
* @param string $clientIp
* @param float $minScore
* @return void
*/
public function __construct($clientIp, $minScore = null)
{
$this->clientIp = $clientIp;
if(is_float($minScore)) {
$this->minScore = $minScore;
}
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
if(app()->environment() === 'local')
{
return true;
}
try {
$score = $this->getRecaptchaScore($value);
} catch (\Exception $exception) {
Bugsnag::notifyException($exception);
return false;
}
return $score >= $this->minScore;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'Not a valid request.';
}
/**
* Creates the multipart form data for the request
* @param string $token
* @return array
*/
protected function createFormData($token)
{
$formData = [
[
'name' => 'secret',
'contents' => config('services.recaptcha.secret_key'),
],
[
'name' => 'response',
'contents' => $token
]
];
if($this->clientIp)
{
$formData[] = [
'name' => 'remoteip',
'contents' => $this->clientIp,
];
}
return $formData;
}
/**
* Creates and executes the request to google's recaptcha service
* and returns the recaptcha score
*
* @throws \Exception
* @param string $token
* @return float
*/
protected function getRecaptchaScore($token)
{
$formData = $this->createFormData($token);
Bugsnag::leaveBreadcrumb('attempting recaptcha', 'recaptcha', [
'formData' => $formData,
'request' => request()->all()
]);
$client = new Client();
$response = $client->post('https://www.google.com/recaptcha/api/siteverify', [
'multipart' => $formData,
'timeout' => 4
]);
$reply = json_decode($response->getBody()->getContents(), true);
Log::info('Reply from recaptcha', [
'response' => $reply,
'formData' => $formData,
'request' => request()->all(),
]);
if( ! array_get($reply, 'success'))
{
throw new \Exception('Non success response from recaptcha', 400);
}
return array_get($reply, 'score', 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment