diff --git a/Docs/Documentation/Configuration.md b/Docs/Documentation/Configuration.md index 01b960aa4..64ee6a8b6 100644 --- a/Docs/Documentation/Configuration.md +++ b/Docs/Documentation/Configuration.md @@ -54,6 +54,7 @@ and add this to your config/users.php file: ```php 'Users.reCaptcha.key' => 'YOUR RECAPTCHA KEY', 'Users.reCaptcha.secret' => 'YOUR RECAPTCHA SECRET', +'Users.reCaptcha.version' => '2', //defaults to version 2 (backward compatibility) but you can use version 3 which is recommended 'Users.reCaptcha.registration' => true, //enable on registration 'Users.reCaptcha.login' => true, //enable on login ``` diff --git a/config/users.php b/config/users.php index 3f347e18e..41cb241f7 100644 --- a/config/users.php +++ b/config/users.php @@ -71,6 +71,8 @@ 'key' => null, // reCaptcha secret 'secret' => null, + // reCaptcha version. keep 2 for backward compatibility + 'version' => 2, // use reCaptcha in registration 'registration' => false, // use reCaptcha in login, valid values are false, true diff --git a/src/View/Helper/UserHelper.php b/src/View/Helper/UserHelper.php index 691ec0fce..eb2226d40 100644 --- a/src/View/Helper/UserHelper.php +++ b/src/View/Helper/UserHelper.php @@ -167,11 +167,26 @@ public function addReCaptcha() ); } $this->addReCaptchaScript(); - try { - $this->Form->unlockField('g-recaptcha-response'); - } catch (\Exception $e) { + $version = Configure::read('Users.reCaptcha.version',2); + $method = "addReCaptchaV$version"; + if (method_exists($this, $method)) { + try { + $this->Form->unlockField('g-recaptcha-response'); + } catch (\Exception $e) { + } + return $this->{$method}(); } + throw new \InvalidArgumentException(__d('cake_d_c/users', 'reCaptcha version is wrong. Please configure Users.reCaptcha.version as 2 or 3')); + + } + /** + * Add required element for reCaptcha v2 + * + * @return string + */ + private function addReCaptchaV2() + { return $this->Html->tag('div', '', [ 'class' => 'g-recaptcha', 'data-sitekey' => Configure::read('Users.reCaptcha.key'), @@ -181,6 +196,35 @@ public function addReCaptcha() ]); } + /** + * Add required script for reCaptcha v3 + */ + private function addReCaptchaV3() + { + $this->Html->script('CakeDC/Users.reCaptchaV3', [ + 'block' => 'script', + ]); + } + + /** + * Add required options for reCaptcha v3 + * + * @return string + */ + public function button($title, $options = []) + { + if (($key = Configure::read('Users.reCaptcha.key')) && Configure::read('Users.reCaptcha.version', 2) === 3) { + $options = array_merge($options, [ + 'class' => 'g-recaptcha', + 'data-sitekey' => $key, + 'data-callback' => 'onSubmit', + 'data-action' => 'submit', + ]); + } + + return $button = $this->Form->button($title, $options); + } + /** * Generate a link if the target url is authorized for the logged in user * diff --git a/templates/Users/register.php b/templates/Users/register.php index e82673b67..1216b4599 100644 --- a/templates/Users/register.php +++ b/templates/Users/register.php @@ -35,6 +35,6 @@ } ?> - Form->button(__d('cake_d_c/users', 'Submit')) ?> + User->button(__d('cake_d_c/users', 'Submit')) ?> Form->end() ?> diff --git a/tests/TestCase/View/Helper/UserHelperTest.php b/tests/TestCase/View/Helper/UserHelperTest.php index a277ec50a..fbe7b12ef 100644 --- a/tests/TestCase/View/Helper/UserHelperTest.php +++ b/tests/TestCase/View/Helper/UserHelperTest.php @@ -51,6 +51,15 @@ class UserHelperTest extends TestCase */ private $AuthLink; + /** + * @var (\Cake\View\View&\PHPUnit\Framework\MockObject\MockObject)|\PHPUnit\Framework\MockObject\MockObject + */ + private $View; + + /** + * @var ServerRequest + */ + private $request; /** * setUp method * @@ -236,6 +245,48 @@ public function testAddReCaptcha() $result = $this->User->addReCaptcha(); $this->assertEquals('
', $result); } + /** + * Test add ReCaptcha V3 + * + * @return void + */ + public function testAddReCaptchaV3() + { + $this->View->expects($this->once()) + ->method('append') + ->with('script', $this->stringContains('https://www.google.com/recaptcha/api.js')); + + Configure::write('Users.reCaptcha.key', 'testKey'); + Configure::write('Users.reCaptcha.version', 3); + Configure::write('Users.reCaptcha.theme', 'light'); + Configure::write('Users.reCaptcha.size', 'normal'); + Configure::write('Users.reCaptcha.tabindex', '3'); + $this->User->Form->create(); + $result = $this->User->addReCaptcha(); + } + + public function testButton() + { + $title = 'test'; + $options = ['test' => 'test']; + $this->assertEquals($this->User->Form->button($title, $options), $this->User->button($title, $options)); + + } + + public function testButtonReCaptchaV3() + { + Configure::write('Users.reCaptcha.key', 'testKey'); + Configure::write('Users.reCaptcha.version', 3); + $title = 'test'; + $options = ['test' => 'test']; + $reCaptchaOptions = [ + 'class' => 'g-recaptcha', + 'data-sitekey' => 'testKey', + 'data-callback' => 'onSubmit', + 'data-action' => 'submit', + ]; + $this->assertEquals($this->User->Form->button($title, array_merge($options, $reCaptchaOptions)), $this->User->button($title, $options)); + } /** * Test add ReCaptcha field diff --git a/webroot/js/reCaptchaV3.js b/webroot/js/reCaptchaV3.js new file mode 100644 index 000000000..42d4d65e7 --- /dev/null +++ b/webroot/js/reCaptchaV3.js @@ -0,0 +1,3 @@ +function onSubmit(token) { + document.forms[0].submit() +}