From 5c6be80b4c760418e6dc7bb55672f4fffae7be73 Mon Sep 17 00:00:00 2001 From: sepiariver Date: Mon, 31 Dec 2018 17:44:38 -0800 Subject: [PATCH] support v3 better --- _build/config.json | 2 +- .../recaptchav2-3.0.0-dev3.transport.zip | Bin 0 -> 63818 bytes .../chunks/recaptchav3_html.chunk.tpl | 5 +- .../snippets/recaptchav2_render.snippet.php | 2 +- .../elements/snippets/recaptchav3.snippet.php | 13 +- .../snippets/recaptchav3_render.snippet.php | 6 +- .../model/recaptchav2/ReCaptcha/ReCaptcha.php | 192 ++++++++++++++++-- .../recaptchav2/ReCaptcha/RequestMethod.php | 2 +- .../ReCaptcha/RequestMethod/Curl.php | 2 +- .../ReCaptcha/RequestMethod/CurlPost.php | 38 ++-- .../ReCaptcha/RequestMethod/Post.php | 36 ++-- .../ReCaptcha/RequestMethod/Socket.php | 12 +- .../ReCaptcha/RequestMethod/SocketPost.php | 49 ++--- .../ReCaptcha/RequestParameters.php | 6 +- .../model/recaptchav2/ReCaptcha/Response.php | 122 ++++++++++- .../model/recaptchav2/autoload.php | 12 +- 16 files changed, 388 insertions(+), 111 deletions(-) create mode 100644 _packages/recaptchav2-3.0.0-dev3.transport.zip mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/ReCaptcha.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Curl.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/CurlPost.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Post.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Socket.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/SocketPost.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestParameters.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/ReCaptcha/Response.php mode change 100644 => 100755 core/components/recaptchav2/model/recaptchav2/autoload.php diff --git a/_build/config.json b/_build/config.json index 52b66ea..2f5fe37 100644 --- a/_build/config.json +++ b/_build/config.json @@ -3,7 +3,7 @@ "lowCaseName" : "recaptchav2", "description" : "ReCaptchaV2 integrates V2 AND V3 of Google's ReCaptcha service into MODX as a FormIt hook.", "author" : "YJ Tso @sepiariver", - "version" : "3.0.0-dev1", + "version" : "3.0.0-dev3", "package" : { "elements" : { "snippets" : [ diff --git a/_packages/recaptchav2-3.0.0-dev3.transport.zip b/_packages/recaptchav2-3.0.0-dev3.transport.zip new file mode 100644 index 0000000000000000000000000000000000000000..d42dace5207f8b90ad639f389d676648e8fd11a7 GIT binary patch literal 63818 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%0DkJL3h`95> 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 A1poj5 literal 0 HcmV?d00001 diff --git a/core/components/recaptchav2/elements/chunks/recaptchav3_html.chunk.tpl b/core/components/recaptchav2/elements/chunks/recaptchav3_html.chunk.tpl index c116b51..5dd3f30 100644 --- a/core/components/recaptchav2/elements/chunks/recaptchav3_html.chunk.tpl +++ b/core/components/recaptchav2/elements/chunks/recaptchav3_html.chunk.tpl @@ -1,7 +1,10 @@ + diff --git a/core/components/recaptchav2/elements/snippets/recaptchav2_render.snippet.php b/core/components/recaptchav2/elements/snippets/recaptchav2_render.snippet.php index abd6574..f074730 100644 --- a/core/components/recaptchav2/elements/snippets/recaptchav2_render.snippet.php +++ b/core/components/recaptchav2/elements/snippets/recaptchav2_render.snippet.php @@ -47,4 +47,4 @@ return true; } else { // This works at least return $recaptcha_html; -} +} \ No newline at end of file diff --git a/core/components/recaptchav2/elements/snippets/recaptchav3.snippet.php b/core/components/recaptchav2/elements/snippets/recaptchav3.snippet.php index 2c28e6f..d0c8c14 100644 --- a/core/components/recaptchav2/elements/snippets/recaptchav3.snippet.php +++ b/core/components/recaptchav2/elements/snippets/recaptchav3.snippet.php @@ -8,7 +8,7 @@ * @link http://www.google.com/recaptcha * * Ported to MODX by YJ Tso @sepiariver - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -35,6 +35,7 @@ $lang = $modx->getOption('cultureKey', null, 'en'); // https://developers.google.com/recaptcha/docs/v3 "Actions" $action_key = $modx->getOption('recaptchav3.action_key', null, 'recaptcha-action', true); +$token_key = $modx->getOption('recaptchav3.token_key', null, 'recaptcha-token', true); // Options if ($hook->formit) { @@ -43,7 +44,7 @@ $threshold = floatval($modx->getOption('recaptchaThreshold', $properties, 0.7, true)); $ip = $modx->getOption('HTTP_CF_CONNECTING_IP', $_SERVER, $_SERVER['REMOTE_ADDR'], true); -// make sure the modLexicon class is loaded by instantiating +// make sure the modLexicon class is loaded by instantiating $modx->getService('lexicon','modLexicon'); // load lexicon $modx->lexicon->load('recaptchav2:default'); @@ -55,14 +56,14 @@ $recaptchaPath = $modx->getOption('recaptchav2.core_path', null, $modx->getOption('core_path') . 'components/recaptchav2/'); $recaptchaPath .= 'model/recaptchav2/'; if (!file_exists($recaptchaPath . 'autoload.php')) { - $modx->log(modX::LOG_LEVEL_ERROR, 'Cannot find required Recaptcha autoload.php file.'); + $modx->log(modX::LOG_LEVEL_ERROR, 'Cannot find required Recaptcha autoload.php file.'); return false; } require_once($recaptchaPath . 'autoload.php'); $recaptcha = new \ReCaptcha\ReCaptcha($secret, new \ReCaptcha\RequestMethod\CurlPost()); if (!($recaptcha instanceof \ReCaptcha\ReCaptcha)) { $hook->addError('recaptchav3_error', $tech_err_msg); - $modx->log(modX::LOG_LEVEL_ERROR, 'Failed to load Recaptcha class.'); + $modx->log(modX::LOG_LEVEL_ERROR, 'Failed to load Recaptcha class.'); return false; } @@ -73,11 +74,11 @@ // Check if being used as hook if (isset($hook)){ // Was there a reCAPTCHA response? - if ($hook->getValue('g-recaptcha-response')) { + if ($hook->getValue($token_key)) { $resp = $recaptcha->setExpectedHostname($_SERVER['SERVER_NAME']) // MODX-y way? ->setExpectedAction($hook->getValue($action_key)) ->setScoreThreshold($threshold) - ->verify($hook->getValue('g-recaptcha-response'), $ip); + ->verify($hook->getValue($token_key), $ip); } // Hook pass/fail diff --git a/core/components/recaptchav2/elements/snippets/recaptchav3_render.snippet.php b/core/components/recaptchav2/elements/snippets/recaptchav3_render.snippet.php index b8bbead..b865717 100644 --- a/core/components/recaptchav2/elements/snippets/recaptchav3_render.snippet.php +++ b/core/components/recaptchav2/elements/snippets/recaptchav3_render.snippet.php @@ -34,6 +34,7 @@ $lang = $modx->getOption('cultureKey', null, 'en', true); // https://developers.google.com/recaptcha/docs/v3 "Actions" $action_key = $modx->getOption('recaptchav3.action_key', null, 'recaptcha-action', true); +$token_key = $modx->getOption('recaptchav3.token_key', null, 'recaptcha-token', true); // new 'recaptchav3_html' Chunk $tpl = $modx->getOption('tpl', $scriptProperties, 'recaptchav3_html', true); $form_id = $modx->getOption('form_id', $scriptProperties, $modx->resource->get('uri')); @@ -41,11 +42,12 @@ $recaptcha_html = $modx->getChunk($tpl, [ 'site_key' => $site_key, 'lang' => $lang, - 'form_id' => $form_id, + 'form_id' => preg_replace('/[^A-Za-z\/_]/', '', $form_id), 'action_key' => $action_key, + 'token_key' => $token_key, ]); -if ($hook) { +if ($hook) { $hook->setValue('recaptchav3_html', $recaptcha_html); // This won't re-render on page reload there's validation errors return true; } else { // This works at least diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/ReCaptcha.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/ReCaptcha.php old mode 100644 new mode 100755 index 7139fae..8939e84 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/ReCaptcha.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/ReCaptcha.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,11 +35,77 @@ class ReCaptcha * Version of this client library. * @const string */ - const VERSION = 'php_1.1.2'; + const VERSION = 'php_1.2.1'; + + /** + * URL for reCAPTCHA sitevrerify API + * @const string + */ + const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'; + + /** + * Invalid JSON received + * @const string + */ + const E_INVALID_JSON = 'invalid-json'; + + /** + * Could not connect to service + * @const string + */ + const E_CONNECTION_FAILED = 'connection-failed'; + + /** + * Did not receive a 200 from the service + * @const string + */ + const E_BAD_RESPONSE = 'bad-response'; + + /** + * Not a success, but no error codes received! + * @const string + */ + const E_UNKNOWN_ERROR = 'unknown-error'; + + /** + * ReCAPTCHA response not provided + * @const string + */ + const E_MISSING_INPUT_RESPONSE = 'missing-input-response'; + + /** + * Expected hostname did not match + * @const string + */ + const E_HOSTNAME_MISMATCH = 'hostname-mismatch'; + + /** + * Expected APK package name did not match + * @const string + */ + const E_APK_PACKAGE_NAME_MISMATCH = 'apk_package_name-mismatch'; + + /** + * Expected action did not match + * @const string + */ + const E_ACTION_MISMATCH = 'action-mismatch'; + + /** + * Score threshold not met + * @const string + */ + const E_SCORE_THRESHOLD_NOT_MET = 'score-threshold-not-met'; + + /** + * Challenge timeout + * @const string + */ + const E_CHALLENGE_TIMEOUT = 'challenge-timeout'; /** * Shared secret for the site. - * @var type string + * @var string */ private $secret; @@ -52,8 +118,9 @@ class ReCaptcha /** * Create a configured instance to use the reCAPTCHA service. * - * @param string $secret shared secret between site and reCAPTCHA server. + * @param string $secret The shared key between your site and reCAPTCHA. * @param RequestMethod $requestMethod method used to send the request. Defaults to POST. + * @throws \RuntimeException if $secret is invalid */ public function __construct($secret, RequestMethod $requestMethod = null) { @@ -66,19 +133,14 @@ public function __construct($secret, RequestMethod $requestMethod = null) } $this->secret = $secret; - - if (!is_null($requestMethod)) { - $this->requestMethod = $requestMethod; - } else { - $this->requestMethod = new RequestMethod\Post(); - } + $this->requestMethod = (is_null($requestMethod)) ? new RequestMethod\Post() : $requestMethod; } /** * Calls the reCAPTCHA siteverify API to verify whether the user passes - * CAPTCHA test. + * CAPTCHA test and additionally runs any specified additional checks * - * @param string $response The value of 'g-recaptcha-response' in the submitted form. + * @param string $response The user response token provided by reCAPTCHA, verifying the user on your site. * @param string $remoteIp The end user's IP address. * @return Response Response from the service. */ @@ -86,12 +148,114 @@ public function verify($response, $remoteIp = null) { // Discard empty solution submissions if (empty($response)) { - $recaptchaResponse = new Response(false, array('missing-input-response')); + $recaptchaResponse = new Response(false, array(self::E_MISSING_INPUT_RESPONSE)); return $recaptchaResponse; } $params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION); $rawResponse = $this->requestMethod->submit($params); - return Response::fromJson($rawResponse); + $initialResponse = Response::fromJson($rawResponse); + $validationErrors = array(); + + if (isset($this->hostname) && strcasecmp($this->hostname, $initialResponse->getHostname()) !== 0) { + $validationErrors[] = self::E_HOSTNAME_MISMATCH; + } + + if (isset($this->apkPackageName) && strcasecmp($this->apkPackageName, $initialResponse->getApkPackageName()) !== 0) { + $validationErrors[] = self::E_APK_PACKAGE_NAME_MISMATCH; + } + + if (isset($this->action) && strcasecmp($this->action, $initialResponse->getAction()) !== 0) { + $validationErrors[] = self::E_ACTION_MISMATCH; + } + + if (isset($this->threshold) && $this->threshold > $initialResponse->getScore()) { + $validationErrors[] = self::E_SCORE_THRESHOLD_NOT_MET; + } + + if (isset($this->timeoutSeconds)) { + $challengeTs = strtotime($initialResponse->getChallengeTs()); + + if ($challengeTs > 0 && time() - $challengeTs > $this->timeoutSeconds) { + $validationErrors[] = self::E_CHALLENGE_TIMEOUT; + } + } + + if (empty($validationErrors)) { + return $initialResponse; + } + + return new Response( + false, + array_merge($initialResponse->getErrorCodes(), $validationErrors), + $initialResponse->getHostname(), + $initialResponse->getChallengeTs(), + $initialResponse->getApkPackageName(), + $initialResponse->getScore(), + $initialResponse->getAction() + ); + } + + /** + * Provide a hostname to match against in verify() + * This should be without a protocol or trailing slash, e.g. www.google.com + * + * @param string $hostname Expected hostname + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedHostname($hostname) + { + $this->hostname = $hostname; + return $this; + } + + /** + * Provide an APK package name to match against in verify() + * + * @param string $apkPackageName Expected APK package name + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedApkPackageName($apkPackageName) + { + $this->apkPackageName = $apkPackageName; + return $this; + } + + /** + * Provide an action to match against in verify() + * This should be set per page. + * + * @param string $action Expected action + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedAction($action) + { + $this->action = $action; + return $this; + } + + /** + * Provide a threshold to meet or exceed in verify() + * Threshold should be a float between 0 and 1 which will be tested as response >= threshold. + * + * @param float $threshold Expected threshold + * @return ReCaptcha Current instance for fluent interface + */ + public function setScoreThreshold($threshold) + { + $this->threshold = floatval($threshold); + return $this; + } + + /** + * Provide a timeout in seconds to test against the challenge timestamp in verify() + * + * @param int $timeoutSeconds Expected hostname + * @return ReCaptcha Current instance for fluent interface + */ + public function setChallengeTimeout($timeoutSeconds) + { + $this->timeoutSeconds = $timeoutSeconds; + return $this; } } diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod.php old mode 100644 new mode 100755 index fc4dde5..2fd94b3 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Curl.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Curl.php old mode 100644 new mode 100755 index 20ee530..3d8dddd --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Curl.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Curl.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/CurlPost.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/CurlPost.php old mode 100644 new mode 100755 index e06d1cc..59886f8 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/CurlPost.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/CurlPost.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ namespace ReCaptcha\RequestMethod; +use ReCaptcha\ReCaptcha; use ReCaptcha\RequestMethod; use ReCaptcha\RequestParameters; @@ -36,25 +37,28 @@ */ class CurlPost implements RequestMethod { - /** - * URL to which requests are sent via cURL. - * @const string - */ - const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'; - /** * Curl connection to the reCAPTCHA service * @var Curl */ private $curl; - public function __construct(Curl $curl = null) + /** + * URL for reCAPTCHA sitevrerify API + * @var string + */ + private $siteVerifyUrl; + + /** + * Only needed if you want to override the defaults + * + * @param Curl $curl Curl resource + * @param string $siteVerifyUrl URL for reCAPTCHA sitevrerify API + */ + public function __construct(Curl $curl = null, $siteVerifyUrl = null) { - if (!is_null($curl)) { - $this->curl = $curl; - } else { - $this->curl = new Curl(); - } + $this->curl = (is_null($curl)) ? new Curl() : $curl; + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; } /** @@ -65,7 +69,7 @@ public function __construct(Curl $curl = null) */ public function submit(RequestParameters $params) { - $handle = $this->curl->init(self::SITE_VERIFY_URL); + $handle = $this->curl->init($this->siteVerifyUrl); $options = array( CURLOPT_POST => true, @@ -83,6 +87,10 @@ public function submit(RequestParameters $params) $response = $this->curl->exec($handle); $this->curl->close($handle); - return $response; + if ($response !== false) { + return $response; + } + + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; } } diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Post.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Post.php old mode 100644 new mode 100755 index 7770d90..9e26582 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Post.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Post.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ namespace ReCaptcha\RequestMethod; +use ReCaptcha\ReCaptcha; use ReCaptcha\RequestMethod; use ReCaptcha\RequestParameters; @@ -35,10 +36,20 @@ class Post implements RequestMethod { /** - * URL to which requests are POSTed. - * @const string + * URL for reCAPTCHA sitevrerify API + * @var string */ - const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'; + private $siteVerifyUrl; + + /** + * Only needed if you want to override the defaults + * + * @param string $siteVerifyUrl URL for reCAPTCHA sitevrerify API + */ + public function __construct($siteVerifyUrl = null) + { + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } /** * Submit the POST request with the specified parameters. @@ -48,23 +59,22 @@ class Post implements RequestMethod */ public function submit(RequestParameters $params) { - /** - * PHP 5.6.0 changed the way you specify the peer name for SSL context options. - * Using "CN_name" will still work, but it will raise deprecated errors. - */ - $peer_key = version_compare(PHP_VERSION, '5.6.0', '<') ? 'CN_name' : 'peer_name'; $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => $params->toQueryString(), - // Force the peer to validate (not needed in 5.6.0+, but still works + // Force the peer to validate (not needed in 5.6.0+, but still works) 'verify_peer' => true, - // Force the peer validation to use www.google.com - $peer_key => 'www.google.com', ), ); $context = stream_context_create($options); - return file_get_contents(self::SITE_VERIFY_URL, false, $context); + $response = file_get_contents($this->siteVerifyUrl, false, $context); + + if ($response !== false) { + return $response; + } + + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; } } diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Socket.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Socket.php old mode 100644 new mode 100755 index f51f123..12322e8 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Socket.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/Socket.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ class Socket /** * fsockopen - * + * * @see http://php.net/fsockopen * @param string $hostname * @param int $port @@ -57,7 +57,7 @@ public function fsockopen($hostname, $port = -1, &$errno = 0, &$errstr = '', $ti /** * fwrite - * + * * @see http://php.net/fwrite * @param string $string * @param int $length @@ -70,7 +70,7 @@ public function fwrite($string, $length = null) /** * fgets - * + * * @see http://php.net/fgets * @param int $length * @return string @@ -82,7 +82,7 @@ public function fgets($length = null) /** * feof - * + * * @see http://php.net/feof * @return bool */ @@ -93,7 +93,7 @@ public function feof() /** * fclose - * + * * @see http://php.net/fclose * @return bool */ diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/SocketPost.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/SocketPost.php old mode 100644 new mode 100755 index 4754121..ca1ca90 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/SocketPost.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestMethod/SocketPost.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,37 +26,17 @@ namespace ReCaptcha\RequestMethod; +use ReCaptcha\ReCaptcha; use ReCaptcha\RequestMethod; use ReCaptcha\RequestParameters; /** * Sends a POST request to the reCAPTCHA service, but makes use of fsockopen() * instead of get_file_contents(). This is to account for people who may be on - * servers where allow_furl_open is disabled. + * servers where allow_url_open is disabled. */ class SocketPost implements RequestMethod { - /** - * reCAPTCHA service host. - * @const string - */ - const RECAPTCHA_HOST = 'www.google.com'; - - /** - * @const string reCAPTCHA service path - */ - const SITE_VERIFY_PATH = '/recaptcha/api/siteverify'; - - /** - * @const string Bad request error - */ - const BAD_REQUEST = '{"success": false, "error-codes": ["invalid-request"]}'; - - /** - * @const string Bad response error - */ - const BAD_RESPONSE = '{"success": false, "error-codes": ["invalid-response"]}'; - /** * Socket to the reCAPTCHA service * @var Socket @@ -64,17 +44,15 @@ class SocketPost implements RequestMethod private $socket; /** - * Constructor + * Only needed if you want to override the defaults * * @param \ReCaptcha\RequestMethod\Socket $socket optional socket, injectable for testing + * @param string $siteVerifyUrl URL for reCAPTCHA sitevrerify API */ - public function __construct(Socket $socket = null) + public function __construct(Socket $socket = null, $siteVerifyUrl = null) { - if (!is_null($socket)) { - $this->socket = $socket; - } else { - $this->socket = new Socket(); - } + $this->socket = (is_null($socket)) ? new Socket() : $socket; + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; } /** @@ -87,15 +65,16 @@ public function submit(RequestParameters $params) { $errno = 0; $errstr = ''; + $urlParsed = parse_url($this->siteVerifyUrl); - if (false === $this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30)) { - return self::BAD_REQUEST; + if (false === $this->socket->fsockopen('ssl://' . $urlParsed['host'], 443, $errno, $errstr, 30)) { + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; } $content = $params->toQueryString(); - $request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n"; - $request .= "Host: " . self::RECAPTCHA_HOST . "\r\n"; + $request = "POST " . $urlParsed['path'] . " HTTP/1.1\r\n"; + $request .= "Host: " . $urlParsed['host'] . "\r\n"; $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; $request .= "Content-length: " . strlen($content) . "\r\n"; $request .= "Connection: close\r\n\r\n"; @@ -111,7 +90,7 @@ public function submit(RequestParameters $params) $this->socket->fclose(); if (0 !== strpos($response, 'HTTP/1.1 200 OK')) { - return self::BAD_RESPONSE; + return '{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}'; } $parts = preg_split("#\n\s*\n#Uis", $response); diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestParameters.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestParameters.php old mode 100644 new mode 100755 index cb66f26..b6dd998 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestParameters.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/RequestParameters.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,13 +32,13 @@ class RequestParameters { /** - * Site secret. + * The shared key between your site and reCAPTCHA. * @var string */ private $secret; /** - * Form response. + * The user response token provided by reCAPTCHA, verifying the user on your site. * @var string */ private $response; diff --git a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/Response.php b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/Response.php old mode 100644 new mode 100755 index d2d8a8b..5c15c37 --- a/core/components/recaptchav2/model/recaptchav2/ReCaptcha/Response.php +++ b/core/components/recaptchav2/model/recaptchav2/ReCaptcha/Response.php @@ -3,7 +3,7 @@ * This is a PHP library that handles calling reCAPTCHA. * * @copyright Copyright (c) 2015, Google Inc. - * @link http://www.google.com/recaptcha + * @link https://www.google.com/recaptcha * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,7 @@ class Response { /** - * Succes or failure. + * Success or failure. * @var boolean */ private $success = false; @@ -43,6 +43,36 @@ class Response */ private $errorCodes = array(); + /** + * The hostname of the site where the reCAPTCHA was solved. + * @var string + */ + private $hostname; + + /** + * Timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ) + * @var string + */ + private $challengeTs; + + /** + * APK package name + * @var string + */ + private $apkPackageName; + + /** + * Score assigned to the request + * @var float + */ + private $score; + + /** + * Action as specified by the page + * @var string + */ + private $action; + /** * Build the response from the expected JSON returned by the service. * @@ -54,29 +84,45 @@ public static function fromJson($json) $responseData = json_decode($json, true); if (!$responseData) { - return new Response(false, array('invalid-json')); + return new Response(false, array(ReCaptcha::E_INVALID_JSON)); } + $hostname = isset($responseData['hostname']) ? $responseData['hostname'] : null; + $challengeTs = isset($responseData['challenge_ts']) ? $responseData['challenge_ts'] : null; + $apkPackageName = isset($responseData['apk_package_name']) ? $responseData['apk_package_name'] : null; + $score = isset($responseData['score']) ? floatval($responseData['score']) : null; + $action = isset($responseData['action']) ? $responseData['action'] : null; + if (isset($responseData['success']) && $responseData['success'] == true) { - return new Response(true); + return new Response(true, array(), $hostname, $challengeTs, $apkPackageName, $score, $action); } if (isset($responseData['error-codes']) && is_array($responseData['error-codes'])) { - return new Response(false, $responseData['error-codes']); + return new Response(false, $responseData['error-codes'], $hostname, $challengeTs, $apkPackageName, $score, $action); } - return new Response(false); + return new Response(false, array(ReCaptcha::E_UNKNOWN_ERROR), $hostname, $challengeTs, $apkPackageName, $score, $action); } /** * Constructor. * * @param boolean $success + * @param string $hostname + * @param string $challengeTs + * @param string $apkPackageName + * @param float $score + * @param strong $action * @param array $errorCodes */ - public function __construct($success, array $errorCodes = array()) + public function __construct($success, array $errorCodes = array(), $hostname = null, $challengeTs = null, $apkPackageName = null, $score = null, $action = null) { $this->success = $success; + $this->hostname = $hostname; + $this->challengeTs = $challengeTs; + $this->apkPackageName = $apkPackageName; + $this->score = $score; + $this->action = $action; $this->errorCodes = $errorCodes; } @@ -99,4 +145,66 @@ public function getErrorCodes() { return $this->errorCodes; } + + /** + * Get hostname. + * + * @return string + */ + public function getHostname() + { + return $this->hostname; + } + + /** + * Get challenge timestamp + * + * @return string + */ + public function getChallengeTs() + { + return $this->challengeTs; + } + + /** + * Get APK package name + * + * @return string + */ + public function getApkPackageName() + { + return $this->apkPackageName; + } + /** + * Get score + * + * @return float + */ + public function getScore() + { + return $this->score; + } + + /** + * Get action + * + * @return string + */ + public function getAction() + { + return $this->action; + } + + public function toArray() + { + return array( + 'success' => $this->isSuccess(), + 'hostname' => $this->getHostname(), + 'challenge_ts' => $this->getChallengeTs(), + 'apk_package_name' => $this->getApkPackageName(), + 'score' => $this->getScore(), + 'action' => $this->getAction(), + 'error-codes' => $this->getErrorCodes(), + ); + } } diff --git a/core/components/recaptchav2/model/recaptchav2/autoload.php b/core/components/recaptchav2/model/recaptchav2/autoload.php old mode 100644 new mode 100755 index a53cbd7..95e249e --- a/core/components/recaptchav2/model/recaptchav2/autoload.php +++ b/core/components/recaptchav2/model/recaptchav2/autoload.php @@ -1,16 +1,16 @@